@edifice.io/react 2.6.9-develop-b2school.20261016112251 → 2.6.9-develop-b2school.20261016170630

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.
Files changed (25) hide show
  1. package/dist/homepage.js +38 -30
  2. package/dist/modules/homepage/components/Cantine/Cantine.d.ts +7 -0
  3. package/dist/modules/homepage/components/Cantine/Cantine.js +44 -0
  4. package/dist/modules/homepage/components/Cantine/CantineContainer.d.ts +4 -0
  5. package/dist/modules/homepage/components/Cantine/CantineContainer.js +18 -0
  6. package/dist/modules/homepage/components/Cantine/CantineModal.d.ts +24 -0
  7. package/dist/modules/homepage/components/Cantine/CantineModal.js +88 -0
  8. package/dist/modules/homepage/components/Cantine/CantineModalContainer.d.ts +7 -0
  9. package/dist/modules/homepage/components/Cantine/CantineModalContainer.js +12 -0
  10. package/dist/modules/homepage/components/Cantine/components/CantineLegend.d.ts +5 -0
  11. package/dist/modules/homepage/components/Cantine/components/CantineLegend.js +22 -0
  12. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.d.ts +6 -0
  13. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.js +28 -0
  14. package/dist/modules/homepage/components/Cantine/components/cantineLabels.d.ts +12 -0
  15. package/dist/modules/homepage/components/Cantine/components/cantineLabels.js +60 -0
  16. package/dist/modules/homepage/components/Cantine/hooks/useCantine.d.ts +11 -0
  17. package/dist/modules/homepage/components/Cantine/hooks/useCantine.js +20 -0
  18. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.d.ts +24 -0
  19. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.js +65 -0
  20. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.d.ts +23 -0
  21. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.js +43 -0
  22. package/dist/modules/homepage/components/Cantine/index.d.ts +7 -0
  23. package/dist/modules/homepage/components/Cantine/types.d.ts +42 -0
  24. package/dist/modules/homepage/components/index.d.ts +1 -0
  25. package/package.json +6 -6
package/dist/homepage.js CHANGED
@@ -1,25 +1,29 @@
1
1
  import { default as default2 } from "./modules/homepage/components/BriefMe/BriefMe.js";
2
- import { default as default3 } from "./modules/homepage/components/Communities/Communities.js";
3
- import { default as default4 } from "./modules/homepage/components/Communities/CommunityItem.js";
4
- import { default as default5 } from "./modules/homepage/components/Communities/CommunitiesSkeleton.js";
5
- import { default as default6 } from "./modules/homepage/components/GenerationHdf/GenerationHdf.js";
6
- import { default as default7 } from "./modules/homepage/components/Header/Header.js";
7
- import { default as default8 } from "./modules/homepage/components/HomeCard/HomeCard.js";
8
- import { default as default9 } from "./modules/homepage/components/LastInfos/LastInfos.js";
9
- import { default as default10 } from "./modules/homepage/components/MessageFlashList/MessageFlash.js";
10
- import { default as default11 } from "./modules/homepage/components/MessageFlashList/MessageFlashList.js";
11
- import { default as default12 } from "./modules/homepage/components/Notifications/NotificationItem.js";
12
- import { default as default13 } from "./modules/homepage/components/Notifications/NotificationList.js";
2
+ import { default as default3 } from "./modules/homepage/components/Cantine/Cantine.js";
3
+ import { default as default4 } from "./modules/homepage/components/Cantine/CantineModal.js";
4
+ import { default as default5 } from "./modules/homepage/components/Communities/Communities.js";
5
+ import { default as default6 } from "./modules/homepage/components/Communities/CommunityItem.js";
6
+ import { default as default7 } from "./modules/homepage/components/Communities/CommunitiesSkeleton.js";
7
+ import { default as default8 } from "./modules/homepage/components/GenerationHdf/GenerationHdf.js";
8
+ import { default as default9 } from "./modules/homepage/components/Header/Header.js";
9
+ import { default as default10 } from "./modules/homepage/components/HomeCard/HomeCard.js";
10
+ import { default as default11 } from "./modules/homepage/components/LastInfos/LastInfos.js";
11
+ import { default as default12 } from "./modules/homepage/components/MessageFlashList/MessageFlash.js";
12
+ import { default as default13 } from "./modules/homepage/components/MessageFlashList/MessageFlashList.js";
13
+ import { default as default14 } from "./modules/homepage/components/Notifications/NotificationItem.js";
14
+ import { default as default15 } from "./modules/homepage/components/Notifications/NotificationList.js";
13
15
  import { NotificationListContainer } from "./modules/homepage/components/Notifications/NotificationListContainer.js";
14
- import { default as default14 } from "./modules/homepage/components/Qwant/Qwant.js";
15
- import { default as default15 } from "./modules/homepage/components/SchoolSpace/SchoolSpace.js";
16
- import { default as default16 } from "./modules/homepage/components/Universalis/Universalis.js";
17
- import { default as default17 } from "./modules/homepage/components/UserSpace/UserSpace.js";
16
+ import { default as default16 } from "./modules/homepage/components/Qwant/Qwant.js";
17
+ import { default as default17 } from "./modules/homepage/components/SchoolSpace/SchoolSpace.js";
18
+ import { default as default18 } from "./modules/homepage/components/Universalis/Universalis.js";
19
+ import { default as default19 } from "./modules/homepage/components/UserSpace/UserSpace.js";
18
20
  import { Agenda } from "./modules/homepage/components/Agenda/Agenda.js";
19
21
  import { AgendaContainer } from "./modules/homepage/components/Agenda/AgendaContainer.js";
20
22
  import { AgendaEventCard } from "./modules/homepage/components/Agenda/AgendaEventCard.js";
21
23
  import { BriefMeContainer } from "./modules/homepage/components/BriefMe/BriefMeContainer.js";
22
24
  import { COMMUNITIES_PREVIEW_SIZE, useCommunities } from "./modules/homepage/components/Communities/useCommunities.js";
25
+ import { CantineContainer } from "./modules/homepage/components/Cantine/CantineContainer.js";
26
+ import { CantineModalContainer } from "./modules/homepage/components/Cantine/CantineModalContainer.js";
23
27
  import { CommunitiesContainer } from "./modules/homepage/components/Communities/CommunitiesContainer.js";
24
28
  import { Favorites } from "./modules/homepage/components/Favorites/Favorites.js";
25
29
  import { FavoritesContainer } from "./modules/homepage/components/Favorites/FavoritesContainer.js";
@@ -46,37 +50,41 @@ export {
46
50
  default2 as BriefMe,
47
51
  BriefMeContainer,
48
52
  COMMUNITIES_PREVIEW_SIZE,
49
- default3 as Communities,
53
+ default3 as Cantine,
54
+ CantineContainer,
55
+ default4 as CantineModal,
56
+ CantineModalContainer,
57
+ default5 as Communities,
50
58
  CommunitiesContainer,
51
- default4 as CommunitiesItem,
52
- default5 as CommunitiesSkeleton,
59
+ default6 as CommunitiesItem,
60
+ default7 as CommunitiesSkeleton,
53
61
  Favorites,
54
62
  FavoritesContainer,
55
- default6 as GenerationHdf,
63
+ default8 as GenerationHdf,
56
64
  GenerationHdfContainer,
57
- default7 as Header,
58
- default8 as HomeCard,
59
- default9 as LastInfos,
65
+ default9 as Header,
66
+ default10 as HomeCard,
67
+ default11 as LastInfos,
60
68
  LastInfosContainer,
61
69
  LastInfosList,
62
70
  LinkForm,
63
71
  MAX_USEFUL_LINKS,
64
- default10 as MessageFlash,
65
- default11 as MessageFlashList,
72
+ default12 as MessageFlash,
73
+ default13 as MessageFlashList,
66
74
  MessageFlashListContainer,
67
- default12 as NotificationItem,
68
- default13 as NotificationList,
75
+ default14 as NotificationItem,
76
+ default15 as NotificationList,
69
77
  NotificationListContainer,
70
- default14 as Qwant,
78
+ default16 as Qwant,
71
79
  QwantContainer,
72
- default15 as SchoolSpace,
80
+ default17 as SchoolSpace,
73
81
  SchoolSpaceContainer,
74
- default16 as Universalis,
82
+ default18 as Universalis,
75
83
  UniversalisContainer,
76
84
  UsefulLinks,
77
85
  UsefulLinksContainer,
78
86
  UsefulLinksModal,
79
- default17 as UserSpace,
87
+ default19 as UserSpace,
80
88
  UserSpaceContainer,
81
89
  WidgetToggle,
82
90
  WidgetsPersonalizationPanel,
@@ -0,0 +1,7 @@
1
+ import { CantineSection, CantineStatus } from './types';
2
+ export interface CantineProps {
3
+ status: CantineStatus;
4
+ sections: CantineSection[];
5
+ handleFullScreenClick: () => void;
6
+ }
7
+ export default function Cantine({ status, sections, handleFullScreenClick, }: CantineProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,44 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import illuCantineEmpty from "@edifice.io/bootstrap/dist/images/homepage/cantine/illu-cantine-empty.svg";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconFullScreen from "../../../icons/components/IconFullScreen.js";
5
+ import CantineMenuSection from "./components/CantineMenuSection.js";
6
+ import HomeCard from "../HomeCard/HomeCard.js";
7
+ import ButtonBeta from "../../../../components/ButtonBeta/ButtonBeta.js";
8
+ import TextSkeleton from "../../../../components/Skeleton/TextSkeleton.js";
9
+ import Image from "../../../../components/Image/Image.js";
10
+ function Cantine({
11
+ status,
12
+ sections,
13
+ handleFullScreenClick
14
+ }) {
15
+ const {
16
+ t
17
+ } = useTranslation();
18
+ return /* @__PURE__ */ jsxs(HomeCard, { variant: "primary", className: "cantine", children: [
19
+ /* @__PURE__ */ jsxs("div", { className: "cantine__header", children: [
20
+ /* @__PURE__ */ jsx("h3", { className: "cantine__title", children: t("homepage.widget.cantine.title") }),
21
+ status !== "error" && /* @__PURE__ */ jsx(ButtonBeta, { "aria-label": t("homepage.widget.cantine.open"), onClick: handleFullScreenClick, leftIcon: /* @__PURE__ */ jsx(SvgIconFullScreen, {}), variant: "ghost", color: "tertiary" })
22
+ ] }),
23
+ /* @__PURE__ */ jsxs(HomeCard.Content, { className: "cantine__content", children: [
24
+ status === "loading" && /* @__PURE__ */ jsxs("div", { className: "cantine__loading", "data-testid": "cantine-loading", children: [
25
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine__loading-item" }),
26
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine__loading-item" }),
27
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine__loading-item" })
28
+ ] }),
29
+ status === "error" && /* @__PURE__ */ jsxs("div", { className: "cantine__error", children: [
30
+ /* @__PURE__ */ jsx(Image, { src: illuCantineEmpty, alt: t("homepage.widget.cantine.emptyIllustration"), className: "cantine__error-illu" }),
31
+ /* @__PURE__ */ jsx("p", { className: "cantine__error-message", children: t("homepage.widget.cantine.error") })
32
+ ] }),
33
+ status === "empty" && /* @__PURE__ */ jsxs("div", { className: "cantine__empty", children: [
34
+ /* @__PURE__ */ jsx(Image, { src: illuCantineEmpty, alt: t("homepage.widget.cantine.emptyIllustration"), className: "cantine__empty-illu" }),
35
+ /* @__PURE__ */ jsx("p", { className: "cantine__empty-message", children: t("homepage.widget.cantine.empty") }),
36
+ /* @__PURE__ */ jsx(ButtonBeta, { variant: "outline", rightIcon: /* @__PURE__ */ jsx(SvgIconFullScreen, {}), onClick: handleFullScreenClick, children: t("homepage.widget.cantine.seeMore") })
37
+ ] }),
38
+ status === "default" && /* @__PURE__ */ jsx("ul", { className: "cantine__menu", children: sections.map((section) => /* @__PURE__ */ jsx(CantineMenuSection, { category: section.category, items: section.items }, section.category)) })
39
+ ] })
40
+ ] });
41
+ }
42
+ export {
43
+ Cantine as default
44
+ };
@@ -0,0 +1,4 @@
1
+ export declare function CantineContainer(): import("react/jsx-runtime").JSX.Element;
2
+ export declare namespace CantineContainer {
3
+ var displayName: string;
4
+ }
@@ -0,0 +1,18 @@
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import Cantine from "./Cantine.js";
4
+ import { CantineModalContainer } from "./CantineModalContainer.js";
5
+ import { useCantine } from "./hooks/useCantine.js";
6
+ function CantineContainer() {
7
+ const {
8
+ sections,
9
+ status
10
+ } = useCantine(), [isModalOpen, setIsModalOpen] = useState(!1);
11
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
12
+ /* @__PURE__ */ jsx(Cantine, { status, sections, handleFullScreenClick: () => setIsModalOpen(!0) }),
13
+ isModalOpen && /* @__PURE__ */ jsx(CantineModalContainer, { onClose: () => setIsModalOpen(!1) })
14
+ ] });
15
+ }
16
+ export {
17
+ CantineContainer
18
+ };
@@ -0,0 +1,24 @@
1
+ import { School } from '@edifice.io/client';
2
+ import { CantineMenuType, CantineSection, CantineStatus } from './types';
3
+ export interface CantineModalProps {
4
+ isOpen: boolean;
5
+ onClose: () => void;
6
+ schools: School[];
7
+ selectedSchool?: School;
8
+ onSchoolChange: (schoolId: string) => void;
9
+ hasDinner: boolean;
10
+ menuType: CantineMenuType;
11
+ onMenuTypeChange: (menuType: CantineMenuType) => void;
12
+ date: string;
13
+ canGoPrevious: boolean;
14
+ canGoNext: boolean;
15
+ onPreviousDay: () => void;
16
+ onNextDay: () => void;
17
+ sections: CantineSection[];
18
+ status: CantineStatus;
19
+ }
20
+ declare const CantineModal: {
21
+ ({ isOpen, onClose, schools, selectedSchool, onSchoolChange, hasDinner, menuType, onMenuTypeChange, date, canGoPrevious, canGoNext, onPreviousDay, onNextDay, sections, status, }: CantineModalProps): import("react/jsx-runtime").JSX.Element;
22
+ displayName: string;
23
+ };
24
+ export default CantineModal;
@@ -0,0 +1,88 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import illuCantineEmpty from "@edifice.io/bootstrap/dist/images/homepage/cantine/illu-cantine-empty.svg";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconRafterLeft from "../../../icons/components/IconRafterLeft.js";
5
+ import SvgIconRafterRight from "../../../icons/components/IconRafterRight.js";
6
+ import CantineLegend from "./components/CantineLegend.js";
7
+ import CantineMenuSection from "./components/CantineMenuSection.js";
8
+ import useDate from "../../../../hooks/useDate/useDate.js";
9
+ import ModalBeta from "../../../../components/ModalBeta/ModalBeta.js";
10
+ import FormControl from "../../../../components/Form/FormControl.js";
11
+ import Label from "../../../../components/Label/Label.js";
12
+ import Select from "../../../../components/Select/Select.js";
13
+ import ButtonBeta from "../../../../components/ButtonBeta/ButtonBeta.js";
14
+ import TextSkeleton from "../../../../components/Skeleton/TextSkeleton.js";
15
+ import Image from "../../../../components/Image/Image.js";
16
+ const CantineModal = ({
17
+ isOpen,
18
+ onClose,
19
+ schools,
20
+ selectedSchool,
21
+ onSchoolChange,
22
+ hasDinner,
23
+ menuType,
24
+ onMenuTypeChange,
25
+ date,
26
+ canGoPrevious,
27
+ canGoNext,
28
+ onPreviousDay,
29
+ onNextDay,
30
+ sections,
31
+ status
32
+ }) => {
33
+ const {
34
+ t
35
+ } = useTranslation(), {
36
+ formatDate
37
+ } = useDate(), hasSchoolSelect = schools.length > 1, menuTypeOptions = [{
38
+ value: "lunch",
39
+ label: t("homepage.widget.cantine.lunch")
40
+ }, {
41
+ value: "dinner",
42
+ label: t("homepage.widget.cantine.dinner")
43
+ }];
44
+ return /* @__PURE__ */ jsxs(ModalBeta, { id: "cantine-modal", size: "l", isOpen, onModalClose: onClose, children: [
45
+ /* @__PURE__ */ jsx(ModalBeta.Header, { onModalClose: onClose, children: t("homepage.widget.cantine.title") }),
46
+ /* @__PURE__ */ jsxs(ModalBeta.Body, { className: "cantine-modal", children: [
47
+ /* @__PURE__ */ jsxs("div", { className: "cantine-modal__aside", children: [
48
+ (hasSchoolSelect || hasDinner) && /* @__PURE__ */ jsx("div", { className: "cantine-modal__form", children: /* @__PURE__ */ jsxs("div", { className: "cantine-modal__fields", children: [
49
+ hasSchoolSelect && /* @__PURE__ */ jsxs(FormControl, { id: "cantine-modal-school", className: "cantine-modal__field", children: [
50
+ /* @__PURE__ */ jsx(Label, { className: "cantine-modal__label", children: t("homepage.widget.cantine.school") }),
51
+ /* @__PURE__ */ jsx(Select, { block: !0, placeholderOption: t("homepage.widget.cantine.school"), options: schools.map((school) => ({
52
+ value: school.id,
53
+ label: school.name
54
+ })), selectedValue: selectedSchool && {
55
+ value: selectedSchool.id,
56
+ label: selectedSchool.name
57
+ }, onValueChange: (option) => onSchoolChange(typeof option == "string" ? option : option.value) })
58
+ ] }),
59
+ hasDinner && /* @__PURE__ */ jsxs(FormControl, { id: "cantine-modal-menu", className: "cantine-modal__field", children: [
60
+ /* @__PURE__ */ jsx(Label, { className: "cantine-modal__label", children: t("homepage.widget.cantine.menu") }),
61
+ /* @__PURE__ */ jsx(Select, { block: !0, placeholderOption: t("homepage.widget.cantine.lunch"), options: menuTypeOptions, selectedValue: menuTypeOptions.find((option) => option.value === menuType), onValueChange: (option) => onMenuTypeChange(typeof option == "string" ? option : option.value) })
62
+ ] })
63
+ ] }) }),
64
+ /* @__PURE__ */ jsx(CantineLegend, {})
65
+ ] }),
66
+ /* @__PURE__ */ jsxs("div", { className: "cantine-modal__panel", children: [
67
+ /* @__PURE__ */ jsxs("div", { className: "cantine-modal__nav", children: [
68
+ /* @__PURE__ */ jsx(ButtonBeta, { "aria-label": t("homepage.widget.cantine.previousDay"), leftIcon: /* @__PURE__ */ jsx(SvgIconRafterLeft, {}), variant: "ghost", color: "tertiary", disabled: !canGoPrevious, onClick: onPreviousDay }),
69
+ /* @__PURE__ */ jsx("p", { className: "cantine-modal__date", children: formatDate(date, "dddd D MMMM") }),
70
+ /* @__PURE__ */ jsx(ButtonBeta, { "aria-label": t("homepage.widget.cantine.nextDay"), leftIcon: /* @__PURE__ */ jsx(SvgIconRafterRight, {}), variant: "ghost", color: "tertiary", disabled: !canGoNext, onClick: onNextDay })
71
+ ] }),
72
+ status === "loading" && /* @__PURE__ */ jsxs("div", { className: "cantine-modal__loading", "data-testid": "cantine-modal-loading", children: [
73
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine-modal__loading-item" }),
74
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine-modal__loading-item" }),
75
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "cantine-modal__loading-item" })
76
+ ] }),
77
+ (status === "empty" || status === "error") && /* @__PURE__ */ jsxs("div", { className: "cantine-modal__empty", children: [
78
+ /* @__PURE__ */ jsx(Image, { src: illuCantineEmpty, alt: t("homepage.widget.cantine.emptyIllustration"), className: "cantine-modal__empty-illu" }),
79
+ /* @__PURE__ */ jsx("p", { className: "cantine-modal__empty-message", children: t("homepage.widget.cantine.empty") })
80
+ ] }),
81
+ status === "default" && /* @__PURE__ */ jsx("ul", { className: "cantine-modal__menu", children: sections.map((section) => /* @__PURE__ */ jsx(CantineMenuSection, { category: section.category, items: section.items }, section.category)) })
82
+ ] })
83
+ ] })
84
+ ] });
85
+ };
86
+ export {
87
+ CantineModal as default
88
+ };
@@ -0,0 +1,7 @@
1
+ export interface CantineModalContainerProps {
2
+ onClose: () => void;
3
+ }
4
+ export declare function CantineModalContainer({ onClose }: CantineModalContainerProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare namespace CantineModalContainer {
6
+ var displayName: string;
7
+ }
@@ -0,0 +1,12 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import CantineModal from "./CantineModal.js";
3
+ import { useCantineModal } from "./hooks/useCantineModal.js";
4
+ function CantineModalContainer({
5
+ onClose
6
+ }) {
7
+ const cantineModal = useCantineModal();
8
+ return /* @__PURE__ */ jsx(CantineModal, { isOpen: !0, onClose, ...cantineModal });
9
+ }
10
+ export {
11
+ CantineModalContainer
12
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Meaning of the quality pictograms displayed next to the dishes, plus the
3
+ * legal notice required by the canteen provider.
4
+ */
5
+ export default function CantineLegend(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import { DISH_TAGS } from "./cantineLabels.js";
4
+ import Image from "../../../../../components/Image/Image.js";
5
+ function CantineLegend() {
6
+ const {
7
+ t
8
+ } = useTranslation();
9
+ return /* @__PURE__ */ jsxs("div", { className: "cantine-modal__legend", children: [
10
+ /* @__PURE__ */ jsxs("div", { className: "cantine-modal__legend-list", children: [
11
+ /* @__PURE__ */ jsx("h3", { className: "cantine-modal__legend-title", children: t("homepage.widget.cantine.legend.title") }),
12
+ DISH_TAGS.map((tag) => /* @__PURE__ */ jsxs("p", { className: "cantine-modal__legend-item", children: [
13
+ /* @__PURE__ */ jsx(Image, { src: tag.icon, alt: t(tag.i18nKey, tag.defaultLabel), className: "cantine-modal__legend-icon" }),
14
+ t(tag.i18nKey, tag.defaultLabel)
15
+ ] }, tag.flag))
16
+ ] }),
17
+ /* @__PURE__ */ jsx("p", { className: "cantine-modal__notice", children: t("homepage.widget.cantine.legend.notice") })
18
+ ] });
19
+ }
20
+ export {
21
+ CantineLegend as default
22
+ };
@@ -0,0 +1,6 @@
1
+ import { CantineCategory, CantineDish } from '../types';
2
+ export interface CantineMenuSectionProps {
3
+ category: CantineCategory;
4
+ items: CantineDish[];
5
+ }
6
+ export default function CantineMenuSection({ category, items, }: CantineMenuSectionProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import { CATEGORY_CONFIG, DISH_TAGS } from "./cantineLabels.js";
4
+ import Image from "../../../../../components/Image/Image.js";
5
+ function CantineMenuSection({
6
+ category,
7
+ items
8
+ }) {
9
+ const {
10
+ t
11
+ } = useTranslation(), config = CATEGORY_CONFIG[category];
12
+ return /* @__PURE__ */ jsxs("li", { className: `cantine__section cantine__section-${category}`, children: [
13
+ /* @__PURE__ */ jsxs("div", { className: "cantine__section-header", children: [
14
+ /* @__PURE__ */ jsx("span", { className: "cantine__section-icon", children: /* @__PURE__ */ jsx(Image, { src: config.icon, alt: t(config.i18nKey, config.defaultLabel) }) }),
15
+ /* @__PURE__ */ jsx("h4", { className: "cantine__section-title", children: t(config.i18nKey, config.defaultLabel) })
16
+ ] }),
17
+ /* @__PURE__ */ jsx("ul", { className: "cantine__items", children: items.map((item) => /* @__PURE__ */ jsxs("li", { className: "cantine__item", children: [
18
+ /* @__PURE__ */ jsxs("div", { className: "cantine__item-text", children: [
19
+ /* @__PURE__ */ jsx("p", { className: "cantine__item-label", children: item.label }),
20
+ item.allergens.length > 0 && /* @__PURE__ */ jsx("p", { className: "cantine__item-allergens", children: item.allergens.join(", ") })
21
+ ] }),
22
+ /* @__PURE__ */ jsx("div", { className: "cantine__item-tags", children: DISH_TAGS.filter((tag) => item[tag.flag]).map((tag) => /* @__PURE__ */ jsx(Image, { src: tag.icon, alt: t(tag.i18nKey, tag.defaultLabel), className: "cantine__item-tag" }, tag.flag)) })
23
+ ] }, item.id)) })
24
+ ] });
25
+ }
26
+ export {
27
+ CantineMenuSection as default
28
+ };
@@ -0,0 +1,12 @@
1
+ import { CantineCategory } from '../types';
2
+ export interface IllustratedLabel {
3
+ icon: string;
4
+ i18nKey: string;
5
+ defaultLabel: string;
6
+ }
7
+ export declare const CATEGORY_CONFIG: Record<CantineCategory, IllustratedLabel>;
8
+ /** Boolean quality flags of a dish */
9
+ export type DishFlag = 'vegetarien' | 'faitmaison' | 'bio' | 'local';
10
+ export declare const DISH_TAGS: (IllustratedLabel & {
11
+ flag: DishFlag;
12
+ })[];
@@ -0,0 +1,60 @@
1
+ import illuAccompagnement from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-dish-accompagnement.svg";
2
+ import illuDessert from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-dish-dessert.svg";
3
+ import illuEntree from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-dish-entree.svg";
4
+ import illuLaitage from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-dish-laitage.svg";
5
+ import illuPlat from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-dish-plat.svg";
6
+ import labelBio from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-label-bio.png";
7
+ import labelFaitmaison from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-label-faitmaison.png";
8
+ import labelLocal from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-label-local.png";
9
+ import labelVegetarien from "@edifice.io/bootstrap/dist/images/homepage/cantine/cantine-label-vegetarien.png";
10
+ const CATEGORY_CONFIG = {
11
+ entree: {
12
+ icon: illuEntree,
13
+ i18nKey: "homepage.widget.cantine.category.entree",
14
+ defaultLabel: "Entrée"
15
+ },
16
+ plat: {
17
+ icon: illuPlat,
18
+ i18nKey: "homepage.widget.cantine.category.plat",
19
+ defaultLabel: "Plat"
20
+ },
21
+ accompagnement: {
22
+ icon: illuAccompagnement,
23
+ i18nKey: "homepage.widget.cantine.category.accompagnement",
24
+ defaultLabel: "Accompagnement"
25
+ },
26
+ laitage: {
27
+ icon: illuLaitage,
28
+ i18nKey: "homepage.widget.cantine.category.laitage",
29
+ defaultLabel: "Laitage"
30
+ },
31
+ dessert: {
32
+ icon: illuDessert,
33
+ i18nKey: "homepage.widget.cantine.category.dessert",
34
+ defaultLabel: "Dessert"
35
+ }
36
+ }, DISH_TAGS = [{
37
+ flag: "vegetarien",
38
+ icon: labelVegetarien,
39
+ i18nKey: "homepage.widget.cantine.tag.vegetarien",
40
+ defaultLabel: "Végétarien"
41
+ }, {
42
+ flag: "faitmaison",
43
+ icon: labelFaitmaison,
44
+ i18nKey: "homepage.widget.cantine.tag.faitmaison",
45
+ defaultLabel: "Fait maison"
46
+ }, {
47
+ flag: "bio",
48
+ icon: labelBio,
49
+ i18nKey: "homepage.widget.cantine.tag.bio",
50
+ defaultLabel: "Agriculture biologique"
51
+ }, {
52
+ flag: "local",
53
+ icon: labelLocal,
54
+ i18nKey: "homepage.widget.cantine.tag.local",
55
+ defaultLabel: "Produit local"
56
+ }];
57
+ export {
58
+ CATEGORY_CONFIG,
59
+ DISH_TAGS
60
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Today's lunch menu for the school currently selected by the user (see
3
+ * `useUserSchools`).
4
+ *
5
+ * Only lunch is exposed: the widget design has no lunch/dinner toggle, unlike
6
+ * the modal and the legacy AngularJS widget.
7
+ */
8
+ export declare function useCantine(): {
9
+ sections: import('..').CantineSection[];
10
+ status: import('..').CantineStatus;
11
+ };
@@ -0,0 +1,20 @@
1
+ import { useUserSchools } from "../../../hooks/useUserSchools.js";
2
+ import { useCantineMenu } from "./useCantineMenu.js";
3
+ import useDate from "../../../../../hooks/useDate/useDate.js";
4
+ function useCantine() {
5
+ const {
6
+ selectedSchool
7
+ } = useUserSchools(), {
8
+ formatDate
9
+ } = useDate(), {
10
+ sections,
11
+ status
12
+ } = useCantineMenu((selectedSchool == null ? void 0 : selectedSchool.UAI) ?? "", formatDate(/* @__PURE__ */ new Date(), "YYYY-MM-DD"));
13
+ return {
14
+ sections,
15
+ status
16
+ };
17
+ }
18
+ export {
19
+ useCantine
20
+ };
@@ -0,0 +1,24 @@
1
+ import { CantineMenuItem, CantineMenus, CantineMenuType, CantineSection, CantineStatus } from '../types';
2
+ export declare function buildSections(menu: CantineMenuItem[]): CantineSection[];
3
+ export declare function cantineMenuQueryOptions(uai: string, date: string): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<CantineMenus, Error, CantineMenus, import('@tanstack/react-query').QueryKey>, "queryFn"> & {
4
+ queryFn?: import('@tanstack/react-query').QueryFunction<CantineMenus, import('@tanstack/react-query').QueryKey, never> | undefined;
5
+ } & {
6
+ queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, CantineMenus>;
7
+ };
8
+ /**
9
+ * Loads one day's menu for one school and groups the requested service's
10
+ * dishes by category. Shared by the widget and its full-screen modal.
11
+ *
12
+ * `loading` also covers "no school selected yet": an absent UAI leaves
13
+ * `enabled: false`, so the query never starts.
14
+ *
15
+ * When the day or the school has no dinner service, the returned `menuType`
16
+ * falls back on lunch: the caller keeps its own request untouched and simply
17
+ * renders what is actually served.
18
+ */
19
+ export declare function useCantineMenu(uai: string, date: string, requestedMenuType?: CantineMenuType): {
20
+ sections: CantineSection[];
21
+ dinnerAvailable: boolean;
22
+ menuType: CantineMenuType;
23
+ status: CantineStatus;
24
+ };
@@ -0,0 +1,65 @@
1
+ import { odeServices } from "@edifice.io/client";
2
+ import { useQuery, queryOptions } from "@tanstack/react-query";
3
+ import { useMemo } from "react";
4
+ const CANTINE_CATEGORIES = ["entree", "plat", "accompagnement", "laitage", "dessert"];
5
+ function getAllergens(item) {
6
+ return Object.keys(item).filter((key) => key.startsWith("allerg_") && item[key] !== 0 && item[key] !== void 0).map((key) => key.slice(7).replace(/_/g, " "));
7
+ }
8
+ function normalizeDish(item, index) {
9
+ var _a;
10
+ const designation = (_a = item.designationMenu) == null ? void 0 : _a.trim();
11
+ return {
12
+ id: `${item.type}-${index}`,
13
+ label: designation || item.nom,
14
+ vegetarien: !!item.vegetarien,
15
+ faitmaison: !!item.faitmaison,
16
+ bio: !!item.bio,
17
+ local: !!item.local,
18
+ allergens: getAllergens(item)
19
+ };
20
+ }
21
+ function buildSections(menu) {
22
+ return CANTINE_CATEGORIES.map((category) => ({
23
+ category,
24
+ items: menu.filter((item) => item.type === category).map((item, index) => normalizeDish(item, index))
25
+ })).filter((section) => section.items.length > 0);
26
+ }
27
+ function cantineMenuQueryOptions(uai, date) {
28
+ return queryOptions({
29
+ queryKey: ["cantine", uai, date],
30
+ enabled: !!uai,
31
+ // The menu is keyed by day and proxied from a slow upstream service, so
32
+ // this caches it for 5 minutes instead of refetching on every remount.
33
+ staleTime: 5 * 60 * 1e3,
34
+ // 5 minutes
35
+ queryFn: async () => {
36
+ const http = odeServices.http(), body = await http.get(`/appregistry/${encodeURIComponent(uai)}/cantine/menu?date=${date}`);
37
+ if (http.isResponseError())
38
+ throw new Error(http.latestResponse.statusText);
39
+ const lunch = Array.isArray(body == null ? void 0 : body.menu) ? body.menu : [], dinner = Array.isArray(body == null ? void 0 : body.dinnerMenu) ? body.dinnerMenu : [];
40
+ return {
41
+ lunch,
42
+ dinner,
43
+ dinnerAvailable: (body == null ? void 0 : body.dinnerAvailable) === !0 && dinner.length > 0
44
+ };
45
+ }
46
+ });
47
+ }
48
+ function useCantineMenu(uai, date, requestedMenuType = "lunch") {
49
+ const {
50
+ data,
51
+ isPending,
52
+ error
53
+ } = useQuery(cantineMenuQueryOptions(uai, date)), dinnerAvailable = (data == null ? void 0 : data.dinnerAvailable) === !0, menuType = requestedMenuType === "dinner" && dinnerAvailable ? "dinner" : "lunch", sections = useMemo(() => buildSections((menuType === "lunch" ? data == null ? void 0 : data.lunch : data == null ? void 0 : data.dinner) ?? []), [data, menuType]);
54
+ return {
55
+ sections,
56
+ dinnerAvailable,
57
+ menuType,
58
+ status: error ? "error" : !uai || isPending ? "loading" : sections.length > 0 ? "default" : "empty"
59
+ };
60
+ }
61
+ export {
62
+ buildSections,
63
+ cantineMenuQueryOptions,
64
+ useCantineMenu
65
+ };
@@ -0,0 +1,23 @@
1
+ import { CantineMenuType } from '../types';
2
+ /**
3
+ * Browsing state of the full-screen canteen modal: day, school and service.
4
+ *
5
+ * The school picked here stays local to the modal on purpose: it must not
6
+ * change the school shared with the other homepage widgets (see
7
+ * `useUserSchools`), only the menu being read.
8
+ */
9
+ export declare function useCantineModal(): {
10
+ schools: import('@edifice.io/client').School[];
11
+ selectedSchool: import('@edifice.io/client').School | undefined;
12
+ onSchoolChange: import('react').Dispatch<import('react').SetStateAction<string | undefined>>;
13
+ hasDinner: boolean;
14
+ menuType: CantineMenuType;
15
+ onMenuTypeChange: import('react').Dispatch<import('react').SetStateAction<CantineMenuType>>;
16
+ date: string;
17
+ canGoPrevious: boolean;
18
+ canGoNext: boolean;
19
+ onPreviousDay: () => void;
20
+ onNextDay: () => void;
21
+ sections: import('..').CantineSection[];
22
+ status: import('..').CantineStatus;
23
+ };
@@ -0,0 +1,43 @@
1
+ import { useState, useMemo } from "react";
2
+ import { useUserSchools } from "../../../hooks/useUserSchools.js";
3
+ import { useCantineMenu } from "./useCantineMenu.js";
4
+ import useDate from "../../../../../hooks/useDate/useDate.js";
5
+ const DATE_RANGE_IN_DAYS = 40, DATE_FORMAT = "YYYY-MM-DD", addDays = (date, days) => {
6
+ const shifted = new Date(date);
7
+ return shifted.setDate(shifted.getDate() + days), shifted;
8
+ };
9
+ function useCantineModal() {
10
+ const {
11
+ schools,
12
+ selectedSchool: defaultSchool
13
+ } = useUserSchools(), {
14
+ formatDate
15
+ } = useDate(), [schoolId, setSchoolId] = useState(), [menuType, setMenuType] = useState("lunch"), [date, setDate] = useState(() => formatDate(/* @__PURE__ */ new Date(), DATE_FORMAT)), {
16
+ minDate,
17
+ maxDate
18
+ } = useMemo(() => {
19
+ const today = /* @__PURE__ */ new Date();
20
+ return {
21
+ minDate: formatDate(addDays(today, -DATE_RANGE_IN_DAYS), DATE_FORMAT),
22
+ maxDate: formatDate(addDays(today, DATE_RANGE_IN_DAYS), DATE_FORMAT)
23
+ };
24
+ }, [formatDate]), selectedSchool = schools.find((school) => school.id === schoolId) ?? defaultSchool, menu = useCantineMenu((selectedSchool == null ? void 0 : selectedSchool.UAI) ?? "", date, menuType), shiftDate = (days) => setDate((current) => formatDate(addDays(/* @__PURE__ */ new Date(`${current}T00:00:00`), days), DATE_FORMAT));
25
+ return {
26
+ schools,
27
+ selectedSchool,
28
+ onSchoolChange: setSchoolId,
29
+ hasDinner: menu.dinnerAvailable,
30
+ menuType: menu.menuType,
31
+ onMenuTypeChange: setMenuType,
32
+ date,
33
+ canGoPrevious: date > minDate,
34
+ canGoNext: date < maxDate,
35
+ onPreviousDay: () => shiftDate(-1),
36
+ onNextDay: () => shiftDate(1),
37
+ sections: menu.sections,
38
+ status: menu.status
39
+ };
40
+ }
41
+ export {
42
+ useCantineModal
43
+ };
@@ -0,0 +1,7 @@
1
+ export * from './Cantine';
2
+ export { default as Cantine } from './Cantine';
3
+ export * from './CantineContainer';
4
+ export * from './CantineModal';
5
+ export { default as CantineModal } from './CantineModal';
6
+ export * from './CantineModalContainer';
7
+ export type { CantineCategory, CantineDish, CantineMenuType, CantineSection, CantineStatus, } from './types';
@@ -0,0 +1,42 @@
1
+ export type CantineCategory = 'entree' | 'plat' | 'accompagnement' | 'laitage' | 'dessert';
2
+ /**
3
+ * Raw dish shape returned by the Webgerest upstream API, forwarded unmapped by
4
+ * app-registry. Everything besides `type` and `nom` is effectively optional.
5
+ */
6
+ export interface CantineMenuItem {
7
+ type: string;
8
+ nom: string;
9
+ designationMenu?: string;
10
+ vegetarien?: boolean;
11
+ faitmaison?: boolean;
12
+ bio?: boolean;
13
+ local?: boolean;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface CantineMenuResponse {
17
+ menu?: CantineMenuItem[];
18
+ dinnerAvailable?: boolean;
19
+ dinnerMenu?: CantineMenuItem[];
20
+ }
21
+ export interface CantineDish {
22
+ id: string;
23
+ label: string;
24
+ vegetarien: boolean;
25
+ faitmaison: boolean;
26
+ bio: boolean;
27
+ local: boolean;
28
+ allergens: string[];
29
+ }
30
+ export interface CantineSection {
31
+ category: CantineCategory;
32
+ items: CantineDish[];
33
+ }
34
+ /** Both services of a given day, as exposed by app-registry. */
35
+ export interface CantineMenus {
36
+ lunch: CantineMenuItem[];
37
+ dinner: CantineMenuItem[];
38
+ /** True when the school also serves a dinner menu that day. */
39
+ dinnerAvailable: boolean;
40
+ }
41
+ export type CantineStatus = 'loading' | 'default' | 'empty' | 'error';
42
+ export type CantineMenuType = 'lunch' | 'dinner';
@@ -1,6 +1,7 @@
1
1
  export * from './Agenda';
2
2
  export * from './Communities';
3
3
  export * from './BriefMe';
4
+ export * from './Cantine';
4
5
  export * from './Favorites';
5
6
  export * from './GenerationHdf';
6
7
  export * from './Header';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.6.9-develop-b2school.20261016112251",
3
+ "version": "2.6.9-develop-b2school.20261016170630",
4
4
  "description": "Edifice React Library",
5
5
  "keywords": [
6
6
  "react",
@@ -140,9 +140,9 @@
140
140
  "swiper": "10.1.0",
141
141
  "ua-parser-js": "1.0.36",
142
142
  "zustand": "4.5.7",
143
- "@edifice.io/tiptap-extensions": "2.6.9-develop-b2school.20261016112251",
144
- "@edifice.io/bootstrap": "2.6.9-develop-b2school.20261016112251",
145
- "@edifice.io/utilities": "2.6.9-develop-b2school.20261016112251"
143
+ "@edifice.io/bootstrap": "2.6.9-develop-b2school.20261016170630",
144
+ "@edifice.io/tiptap-extensions": "2.6.9-develop-b2school.20261016170630",
145
+ "@edifice.io/utilities": "2.6.9-develop-b2school.20261016170630"
146
146
  },
147
147
  "devDependencies": {
148
148
  "@babel/plugin-transform-react-pure-annotations": "7.27.1",
@@ -173,8 +173,8 @@
173
173
  "vite": "5.4.14",
174
174
  "vite-plugin-dts": "4.5.4",
175
175
  "vite-tsconfig-paths": "5.1.4",
176
- "@edifice.io/client": "2.6.9-develop-b2school.20261016112251",
177
- "@edifice.io/config": "2.6.9-develop-b2school.20261016112251"
176
+ "@edifice.io/client": "2.6.9-develop-b2school.20261016170630",
177
+ "@edifice.io/config": "2.6.9-develop-b2school.20261016170630"
178
178
  },
179
179
  "peerDependencies": {
180
180
  "@react-spring/web": "9.7.5",