@edifice.io/react 2.6.9-develop.20261013171251 → 2.6.10-develop-b2school.20261019104630

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 (133) hide show
  1. package/dist/components/Layout/Layout.js +12 -4
  2. package/dist/components/Layout/components/Header.js +4 -4
  3. package/dist/components/Layout/components/NavLink.d.ts +3 -3
  4. package/dist/components/Layout/components/NavLink.js +5 -3
  5. package/dist/components/Tree/utilities/tree.js +21 -1
  6. package/dist/homepage.js +62 -24
  7. package/dist/hooks/index.d.ts +2 -0
  8. package/dist/hooks/useBackground/useBackground.d.ts +1 -1
  9. package/dist/hooks/useCarbonioUnread/index.d.ts +1 -0
  10. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.d.ts +5 -0
  11. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.js +24 -0
  12. package/dist/hooks/useNextcloudSearch/index.d.ts +1 -0
  13. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.d.ts +14 -0
  14. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.js +64 -0
  15. package/dist/hooks/useZendeskGuide/useZendeskGuide.d.ts +2 -6
  16. package/dist/hooks/useZendeskGuide/useZendeskGuide.js +11 -8
  17. package/dist/icons.js +404 -402
  18. package/dist/index.js +160 -152
  19. package/dist/modules/HelpZone/HelpZone.js +6 -8
  20. package/dist/modules/HelpZone/HelpZoneContainer.js +2 -5
  21. package/dist/modules/homepage/components/Agenda/Agenda.d.ts +10 -0
  22. package/dist/modules/homepage/components/Agenda/Agenda.js +54 -0
  23. package/dist/modules/homepage/components/Agenda/AgendaContainer.d.ts +1 -0
  24. package/dist/modules/homepage/components/Agenda/AgendaContainer.js +14 -0
  25. package/dist/modules/homepage/components/Agenda/AgendaEventCard.d.ts +10 -0
  26. package/dist/modules/homepage/components/Agenda/AgendaEventCard.js +30 -0
  27. package/dist/modules/homepage/components/Agenda/hooks/useAgendaContainer.d.ts +14 -0
  28. package/dist/modules/homepage/components/Agenda/hooks/useAgendaContainer.js +27 -0
  29. package/dist/modules/homepage/components/Agenda/index.d.ts +3 -0
  30. package/dist/modules/homepage/components/Agenda/services/api/agendaService.d.ts +24 -0
  31. package/dist/modules/homepage/components/Agenda/services/api/agendaService.js +45 -0
  32. package/dist/modules/homepage/components/Agenda/services/api/index.d.ts +4 -0
  33. package/dist/modules/homepage/components/Agenda/services/api/index.js +5 -0
  34. package/dist/modules/homepage/components/Agenda/services/queries/agenda.d.ts +19 -0
  35. package/dist/modules/homepage/components/Agenda/services/queries/agenda.js +26 -0
  36. package/dist/modules/homepage/components/BriefMe/BriefMe.d.ts +9 -0
  37. package/dist/modules/homepage/components/BriefMe/BriefMe.js +59 -0
  38. package/dist/modules/homepage/components/BriefMe/BriefMeContainer.d.ts +4 -0
  39. package/dist/modules/homepage/components/BriefMe/BriefMeContainer.js +17 -0
  40. package/dist/modules/homepage/components/BriefMe/index.d.ts +4 -0
  41. package/dist/modules/homepage/components/BriefMe/types.d.ts +17 -0
  42. package/dist/modules/homepage/components/BriefMe/types.js +8 -0
  43. package/dist/modules/homepage/components/BriefMe/useBriefMe.d.ts +31 -0
  44. package/dist/modules/homepage/components/BriefMe/useBriefMe.js +51 -0
  45. package/dist/modules/homepage/components/Cantine/Cantine.d.ts +7 -0
  46. package/dist/modules/homepage/components/Cantine/Cantine.js +44 -0
  47. package/dist/modules/homepage/components/Cantine/CantineContainer.d.ts +4 -0
  48. package/dist/modules/homepage/components/Cantine/CantineContainer.js +18 -0
  49. package/dist/modules/homepage/components/Cantine/CantineModal.d.ts +24 -0
  50. package/dist/modules/homepage/components/Cantine/CantineModal.js +88 -0
  51. package/dist/modules/homepage/components/Cantine/CantineModalContainer.d.ts +7 -0
  52. package/dist/modules/homepage/components/Cantine/CantineModalContainer.js +12 -0
  53. package/dist/modules/homepage/components/Cantine/components/CantineLegend.d.ts +5 -0
  54. package/dist/modules/homepage/components/Cantine/components/CantineLegend.js +22 -0
  55. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.d.ts +6 -0
  56. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.js +28 -0
  57. package/dist/modules/homepage/components/Cantine/components/cantineLabels.d.ts +12 -0
  58. package/dist/modules/homepage/components/Cantine/components/cantineLabels.js +60 -0
  59. package/dist/modules/homepage/components/Cantine/hooks/useCantine.d.ts +11 -0
  60. package/dist/modules/homepage/components/Cantine/hooks/useCantine.js +20 -0
  61. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.d.ts +24 -0
  62. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.js +65 -0
  63. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.d.ts +23 -0
  64. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.js +43 -0
  65. package/dist/modules/homepage/components/Cantine/index.d.ts +7 -0
  66. package/dist/modules/homepage/components/Cantine/types.d.ts +42 -0
  67. package/dist/modules/homepage/components/Communities/Communities.js +4 -4
  68. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.d.ts +16 -0
  69. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.js +48 -0
  70. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.d.ts +4 -0
  71. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.js +12 -0
  72. package/dist/modules/homepage/components/GenerationHdf/formatSolde.d.ts +1 -0
  73. package/dist/modules/homepage/components/GenerationHdf/formatSolde.js +6 -0
  74. package/dist/modules/homepage/components/GenerationHdf/index.d.ts +3 -0
  75. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.d.ts +10 -0
  76. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.js +68 -0
  77. package/dist/modules/homepage/components/Header/Header.js +37 -14
  78. package/dist/modules/homepage/components/Header/MyAppsPopover.d.ts +5 -0
  79. package/dist/modules/homepage/components/Header/MyAppsPopover.js +28 -0
  80. package/dist/modules/homepage/components/Header/useSafeHoverPopover.js +32 -0
  81. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.d.ts +5 -1
  82. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.js +1 -1
  83. package/dist/modules/homepage/components/MessageFlashList/MessageFlash.js +1 -1
  84. package/dist/modules/homepage/components/Notifications/NotificationList.js +5 -5
  85. package/dist/modules/homepage/components/Notifications/NotificationSkeleton.js +2 -2
  86. package/dist/modules/homepage/components/Notifications/components/NotificationFilterMenu.js +1 -5
  87. package/dist/modules/homepage/components/Notifications/components/NotificationFilterModal.js +10 -12
  88. package/dist/modules/homepage/components/Notifications/components/NotificationOptionsMenu.js +3 -9
  89. package/dist/modules/homepage/components/Notifications/components/ReportNotificationModal.js +6 -12
  90. package/dist/modules/homepage/components/Notifications/components/notificationAdapter.js +12 -10
  91. package/dist/modules/homepage/components/Notifications/hooks/useNotificationList.js +9 -10
  92. package/dist/modules/homepage/components/Qwant/Qwant.d.ts +4 -0
  93. package/dist/modules/homepage/components/Qwant/Qwant.js +41 -0
  94. package/dist/modules/homepage/components/Qwant/QwantContainer.d.ts +1 -0
  95. package/dist/modules/homepage/components/Qwant/QwantContainer.js +10 -0
  96. package/dist/modules/homepage/components/Qwant/index.d.ts +3 -0
  97. package/dist/modules/homepage/components/SchoolSpace/SchoolSpaceContainer.js +1 -1
  98. package/dist/modules/homepage/components/Universalis/Universalis.d.ts +8 -0
  99. package/dist/modules/homepage/components/Universalis/Universalis.js +62 -0
  100. package/dist/modules/homepage/components/Universalis/UniversalisContainer.d.ts +1 -0
  101. package/dist/modules/homepage/components/Universalis/UniversalisContainer.js +16 -0
  102. package/dist/modules/homepage/components/Universalis/index.d.ts +3 -0
  103. package/dist/modules/homepage/components/UserSpace/UserSpace.d.ts +3 -1
  104. package/dist/modules/homepage/components/UserSpace/UserSpace.js +13 -7
  105. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.d.ts +4 -2
  106. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.js +3 -2
  107. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.d.ts +16 -0
  108. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.js +15 -0
  109. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.d.ts +21 -0
  110. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.js +47 -0
  111. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/index.d.ts +2 -0
  112. package/dist/modules/homepage/components/index.d.ts +8 -1
  113. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.d.ts +2 -2
  114. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.js +4 -4
  115. package/dist/modules/icons/components/IconAddWidget.d.ts +7 -0
  116. package/dist/modules/icons/components/IconAddWidget.js +12 -0
  117. package/dist/modules/icons/components/index.d.ts +1 -0
  118. package/dist/modules/multimedia/FileCard/NextcloudFileCard.d.ts +25 -0
  119. package/dist/modules/multimedia/FileCard/NextcloudFileCard.js +102 -0
  120. package/dist/modules/multimedia/FileCard/index.d.ts +2 -0
  121. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.d.ts +2 -2
  122. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.js +36 -11
  123. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.d.ts +1 -0
  124. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.js +48 -0
  125. package/dist/modules/multimedia/MediaLibrary/innertabs/index.d.ts +1 -0
  126. package/dist/modules/multimedia/MediaLibrary/innertabs/index.js +2 -0
  127. package/dist/modules/multimedia/Nextcloud/Nextcloud.d.ts +24 -0
  128. package/dist/modules/multimedia/Nextcloud/Nextcloud.js +120 -0
  129. package/dist/modules/multimedia/Nextcloud/index.d.ts +2 -0
  130. package/dist/modules/multimedia/Workspace/Workspace.js +8 -5
  131. package/dist/modules/multimedia/index.d.ts +1 -0
  132. package/dist/multimedia.js +16 -12
  133. package/package.json +6 -6
@@ -0,0 +1,24 @@
1
+ import { Calendar, CalendarEvent } from '@edifice.io/client';
2
+ /**
3
+ * Creates an agenda service with methods to fetch the current user's
4
+ * calendars and upcoming events (homepage "Agenda" widget).
5
+ *
6
+ * Backend contract (provisional, see IMPULS-5880/IMPULS-6095): `GET
7
+ * /calendar/calendars` lists the user's calendars, `GET
8
+ * /calendar/events/widget?calendarId=...&nb=N` returns up to `N` events for
9
+ * the given calendars. Whether that second endpoint already excludes past
10
+ * (fully elapsed) events isn't guaranteed, so callers should re-apply that
11
+ * filter themselves.
12
+ *
13
+ * @param baseURL The base URL for the agenda service API.
14
+ */
15
+ export declare const createAgendaService: (baseURL: string) => {
16
+ /**
17
+ * Get the calendars the current user can see events from.
18
+ */
19
+ getCalendars(): Promise<Calendar[]>;
20
+ /**
21
+ * Get up to `nb` events for the given calendars, in no particular order.
22
+ */
23
+ getEvents(calendarIds: string[], nb: number): Promise<CalendarEvent[]>;
24
+ };
@@ -0,0 +1,45 @@
1
+ import { odeServices } from "@edifice.io/client";
2
+ const toCalendar = ({
3
+ _id,
4
+ title,
5
+ color,
6
+ isExternal
7
+ }) => ({
8
+ id: _id,
9
+ title,
10
+ color,
11
+ isExternal
12
+ }), toCalendarEvent = ({
13
+ _id,
14
+ title,
15
+ allday,
16
+ startMoment,
17
+ endMoment,
18
+ calendar
19
+ }) => ({
20
+ id: _id,
21
+ calendarId: calendar[0],
22
+ title,
23
+ startMoment,
24
+ endMoment,
25
+ allDay: allday
26
+ }), createAgendaService = (baseURL) => ({
27
+ /**
28
+ * Get the calendars the current user can see events from.
29
+ */
30
+ async getCalendars() {
31
+ return (await odeServices.http().get(`${baseURL}/calendar/calendars`)).map(toCalendar);
32
+ },
33
+ /**
34
+ * Get up to `nb` events for the given calendars, in no particular order.
35
+ */
36
+ async getEvents(calendarIds, nb) {
37
+ if (calendarIds.length === 0)
38
+ return [];
39
+ const query = new URLSearchParams();
40
+ return calendarIds.forEach((id) => query.append("calendarId", id)), query.set("nb", String(nb)), (await odeServices.http().get(`${baseURL}/calendar/events/widget?${query.toString()}`)).map(toCalendarEvent);
41
+ }
42
+ });
43
+ export {
44
+ createAgendaService
45
+ };
@@ -0,0 +1,4 @@
1
+ export declare const agendaService: {
2
+ getCalendars(): Promise<import('@edifice.io/client').Calendar[]>;
3
+ getEvents(calendarIds: string[], nb: number): Promise<import('@edifice.io/client').CalendarEvent[]>;
4
+ };
@@ -0,0 +1,5 @@
1
+ import { createAgendaService } from "./agendaService.js";
2
+ const agendaService = createAgendaService("");
3
+ export {
4
+ agendaService
5
+ };
@@ -0,0 +1,19 @@
1
+ import { Calendar, CalendarEvent } from '@edifice.io/client';
2
+ export declare const agendaQueryKeys: {
3
+ calendars: () => readonly ["agenda", "calendars"];
4
+ events: (calendarIds: string[], nb: number) => readonly ["agenda", "events", string[], number];
5
+ };
6
+ export declare const agendaQueryOptions: {
7
+ getCalendars(): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<Calendar[], Error, Calendar[], import('@tanstack/react-query').QueryKey>, "queryFn"> & {
8
+ queryFn?: import('@tanstack/react-query').QueryFunction<Calendar[], import('@tanstack/react-query').QueryKey, never> | undefined;
9
+ } & {
10
+ queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, Calendar[]>;
11
+ };
12
+ getEvents(calendarIds: string[], nb: number): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<CalendarEvent[], Error, CalendarEvent[], import('@tanstack/react-query').QueryKey>, "queryFn"> & {
13
+ queryFn?: import('@tanstack/react-query').QueryFunction<CalendarEvent[], import('@tanstack/react-query').QueryKey, never> | undefined;
14
+ } & {
15
+ queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, CalendarEvent[]>;
16
+ };
17
+ };
18
+ export declare const useCalendars: () => import('@tanstack/react-query').UseQueryResult<Calendar[], Error>;
19
+ export declare const useEvents: (calendarIds: string[], nb: number) => import('@tanstack/react-query').UseQueryResult<CalendarEvent[], Error>;
@@ -0,0 +1,26 @@
1
+ import { useQuery, queryOptions } from "@tanstack/react-query";
2
+ import { agendaService } from "../api/index.js";
3
+ const agendaQueryKeys = {
4
+ calendars: () => ["agenda", "calendars"],
5
+ events: (calendarIds, nb) => ["agenda", "events", calendarIds, nb]
6
+ }, agendaQueryOptions = {
7
+ getCalendars() {
8
+ return queryOptions({
9
+ queryKey: agendaQueryKeys.calendars(),
10
+ queryFn: async () => agendaService.getCalendars()
11
+ });
12
+ },
13
+ getEvents(calendarIds, nb) {
14
+ return queryOptions({
15
+ queryKey: agendaQueryKeys.events(calendarIds, nb),
16
+ queryFn: async () => agendaService.getEvents(calendarIds, nb),
17
+ enabled: calendarIds.length > 0
18
+ });
19
+ }
20
+ }, useCalendars = () => useQuery(agendaQueryOptions.getCalendars()), useEvents = (calendarIds, nb) => useQuery(agendaQueryOptions.getEvents(calendarIds, nb));
21
+ export {
22
+ agendaQueryKeys,
23
+ agendaQueryOptions,
24
+ useCalendars,
25
+ useEvents
26
+ };
@@ -0,0 +1,9 @@
1
+ import { BriefMeArticle, BriefMeStatus } from './types';
2
+ export interface BriefMeProps {
3
+ handleActionClick: () => void;
4
+ status: BriefMeStatus;
5
+ category: string;
6
+ onCategoryChange: (value: string) => void;
7
+ articles: BriefMeArticle[];
8
+ }
9
+ export default function BriefMe({ handleActionClick, status, category, onCategoryChange, articles, }: BriefMeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,59 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import illuBriefMeError from "@edifice.io/bootstrap/dist/images/homepage/illu-briefme-error.svg";
3
+ import clsx from "clsx";
4
+ import { useTranslation } from "react-i18next";
5
+ import SvgIconExternalLink from "../../../icons/components/IconExternalLink.js";
6
+ import HomeCard from "../HomeCard/HomeCard.js";
7
+ import IconButton from "../../../../components/Button/IconButton.js";
8
+ import SegmentedControl from "../../../../components/SegmentedControl/SegmentedControl.js";
9
+ import TextSkeleton from "../../../../components/Skeleton/TextSkeleton.js";
10
+ import Image from "../../../../components/Image/Image.js";
11
+ function BriefMe({
12
+ handleActionClick,
13
+ status,
14
+ category,
15
+ onCategoryChange,
16
+ articles
17
+ }) {
18
+ const {
19
+ t
20
+ } = useTranslation(), categoryOptions = [{
21
+ label: t("homepage.briefme.category.briefme"),
22
+ value: "briefme"
23
+ }, {
24
+ label: t("homepage.briefme.category.brief-eco"),
25
+ value: "brief-eco"
26
+ }, {
27
+ label: t("homepage.briefme.category.brief-science"),
28
+ value: "brief-science"
29
+ }];
30
+ return /* @__PURE__ */ jsxs(HomeCard, { variant: "primary", className: "briefme", children: [
31
+ /* @__PURE__ */ jsxs("div", { className: "briefme__header", children: [
32
+ /* @__PURE__ */ jsx("h3", { className: "briefme__title", children: t("homepage.briefme.title") }),
33
+ /* @__PURE__ */ jsx(IconButton, { "aria-label": t("homepage.briefme.open"), onClick: handleActionClick, icon: /* @__PURE__ */ jsx(SvgIconExternalLink, {}), variant: "ghost", color: "tertiary" })
34
+ ] }),
35
+ /* @__PURE__ */ jsxs(HomeCard.Content, { className: clsx("briefme__body", `briefme__body--${status}`), children: [
36
+ status !== "error" && /* @__PURE__ */ jsx(SegmentedControl, { "aria-label": t("homepage.briefme.categories"), options: categoryOptions, value: category, onChange: onCategoryChange, className: "briefme__categories" }),
37
+ status === "loading" && /* @__PURE__ */ jsxs("div", { className: "briefme__loading", "data-testid": "briefme-loading", children: [
38
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "briefme__loading-item" }),
39
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "briefme__loading-item" }),
40
+ /* @__PURE__ */ jsx(TextSkeleton, { size: "lg", className: "briefme__loading-item" })
41
+ ] }),
42
+ status === "error" && /* @__PURE__ */ jsxs("div", { className: "briefme__error", children: [
43
+ /* @__PURE__ */ jsx(Image, { src: illuBriefMeError, alt: "", className: "briefme__error-illu" }),
44
+ /* @__PURE__ */ jsxs("p", { className: "briefme__error-message", children: [
45
+ /* @__PURE__ */ jsx("span", { className: "briefme__error-line", children: t("homepage.briefme.error.connection") }),
46
+ /* @__PURE__ */ jsx("span", { className: "briefme__error-line", children: t("homepage.briefme.error.help") })
47
+ ] })
48
+ ] }),
49
+ status === "empty" && /* @__PURE__ */ jsx("p", { className: "briefme__empty", children: t("homepage.briefme.empty") }),
50
+ status === "default" && /* @__PURE__ */ jsx("ul", { className: "briefme__list", children: articles.map((article) => /* @__PURE__ */ jsxs("li", { className: "briefme__article", children: [
51
+ /* @__PURE__ */ jsx("span", { className: "briefme__article-date", children: article.date }),
52
+ /* @__PURE__ */ jsx("a", { className: "briefme__article-title", href: article.url, target: "_blank", rel: "noopener noreferrer", children: article.title })
53
+ ] }, article.id)) })
54
+ ] })
55
+ ] });
56
+ }
57
+ export {
58
+ BriefMe as default
59
+ };
@@ -0,0 +1,4 @@
1
+ export declare function BriefMeContainer(): import("react/jsx-runtime").JSX.Element;
2
+ export declare namespace BriefMeContainer {
3
+ var displayName: string;
4
+ }
@@ -0,0 +1,17 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import BriefMe from "./BriefMe.js";
3
+ import { useBriefMe } from "./useBriefMe.js";
4
+ function BriefMeContainer() {
5
+ const {
6
+ category,
7
+ setCategory,
8
+ articles,
9
+ status
10
+ } = useBriefMe();
11
+ return /* @__PURE__ */ jsx(BriefMe, { handleActionClick: () => {
12
+ window.open("https://brief.me", "_blank", "noopener,noreferrer");
13
+ }, status, category, onCategoryChange: (value) => setCategory(value), articles });
14
+ }
15
+ export {
16
+ BriefMeContainer
17
+ };
@@ -0,0 +1,4 @@
1
+ export * from './BriefMe';
2
+ export { default as BriefMe } from './BriefMe';
3
+ export * from './BriefMeContainer';
4
+ export * from './useBriefMe';
@@ -0,0 +1,17 @@
1
+ export interface BriefMeArticle {
2
+ id: string;
3
+ date: string;
4
+ title: string;
5
+ url: string;
6
+ }
7
+ export type BriefMeStatus = 'loading' | 'default' | 'empty' | 'error';
8
+ /**
9
+ * Brief.me feeds are proxied and cached by app-registry, one endpoint per
10
+ * category. Keys match the SegmentedControl option values of `BriefMe`.
11
+ */
12
+ export declare const BRIEFME_ENDPOINTS: {
13
+ readonly briefme: "/appregistry/widget/cache/external/briefme";
14
+ readonly 'brief-eco': "/appregistry/widget/cache/external/briefeco";
15
+ readonly 'brief-science': "/appregistry/widget/cache/external/briefscience";
16
+ };
17
+ export type BriefMeCategory = keyof typeof BRIEFME_ENDPOINTS;
@@ -0,0 +1,8 @@
1
+ const BRIEFME_ENDPOINTS = {
2
+ briefme: "/appregistry/widget/cache/external/briefme",
3
+ "brief-eco": "/appregistry/widget/cache/external/briefeco",
4
+ "brief-science": "/appregistry/widget/cache/external/briefscience"
5
+ };
6
+ export {
7
+ BRIEFME_ENDPOINTS
8
+ };
@@ -0,0 +1,31 @@
1
+ import { School } from '@edifice.io/client';
2
+ import { BriefMeArticle, BriefMeCategory, BriefMeStatus } from './types';
3
+ interface BriefMeEntry {
4
+ title: string;
5
+ published_at: string;
6
+ url: string;
7
+ }
8
+ /**
9
+ * Article URLs served by Brief.me embed the literal `ID_ETAB` and `ID_ENT`
10
+ * placeholders, which identify the subscribing school to their SSO. Both are
11
+ * replaced by base64-encoded values: the school UAI, and the GAR code taken
12
+ * from its exports.
13
+ */
14
+ export declare function buildGarLink(url: string, school?: School): string;
15
+ export declare function briefMeQueryOptions(category: BriefMeCategory): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<BriefMeEntry[], Error, BriefMeEntry[], import('@tanstack/react-query').QueryKey>, "queryFn"> & {
16
+ queryFn?: import('@tanstack/react-query').QueryFunction<BriefMeEntry[], import('@tanstack/react-query').QueryKey, never> | undefined;
17
+ } & {
18
+ queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, BriefMeEntry[]>;
19
+ };
20
+ /**
21
+ * Loads the Brief.me articles of the selected category (most recent first,
22
+ * capped at `BRIEFME_MAX_ARTICLES`), and resolves their links against the
23
+ * school currently selected by the user.
24
+ */
25
+ export declare function useBriefMe(): {
26
+ category: "briefme" | "brief-eco" | "brief-science";
27
+ setCategory: import('react').Dispatch<import('react').SetStateAction<"briefme" | "brief-eco" | "brief-science">>;
28
+ articles: BriefMeArticle[];
29
+ status: BriefMeStatus;
30
+ };
31
+ export {};
@@ -0,0 +1,51 @@
1
+ import { odeServices } from "@edifice.io/client";
2
+ import { queryOptions, useQuery } from "@tanstack/react-query";
3
+ import { useState, useMemo } from "react";
4
+ import useDate from "../../../../hooks/useDate/useDate.js";
5
+ import { useUserSchools } from "../../hooks/useUserSchools.js";
6
+ import { BRIEFME_ENDPOINTS } from "./types.js";
7
+ const BRIEFME_DEFAULT_CATEGORY = "briefme", BRIEFME_MAX_ARTICLES = 5;
8
+ function buildGarLink(url, school) {
9
+ const schoolExports = (school == null ? void 0 : school.exports) ?? [], garExport = schoolExports.find((entry) => entry.startsWith("GAR-")), garCode = garExport ? garExport.replace("GAR-", "") : schoolExports[0] ?? "";
10
+ return url.replace("ID_ETAB", btoa((school == null ? void 0 : school.UAI) ?? "")).replace("ID_ENT", btoa(garCode));
11
+ }
12
+ function briefMeQueryOptions(category) {
13
+ return queryOptions({
14
+ queryKey: ["briefme", category],
15
+ queryFn: async () => {
16
+ const http = odeServices.http(), feed = await http.get(BRIEFME_ENDPOINTS[category]);
17
+ if (http.isResponseError())
18
+ throw new Error(http.latestResponse.statusText);
19
+ if (!feed || feed.error || !Array.isArray(feed.results))
20
+ throw new Error((feed == null ? void 0 : feed.error) ?? "briefme.invalid.response");
21
+ return feed.results;
22
+ }
23
+ });
24
+ }
25
+ function useBriefMe() {
26
+ const [category, setCategory] = useState(BRIEFME_DEFAULT_CATEGORY), {
27
+ selectedSchool
28
+ } = useUserSchools(), {
29
+ formatDate
30
+ } = useDate(), {
31
+ data,
32
+ isLoading,
33
+ error
34
+ } = useQuery(briefMeQueryOptions(category)), articles = useMemo(() => [...data ?? []].sort((a, b) => new Date(b.published_at).getTime() - new Date(a.published_at).getTime()).slice(0, BRIEFME_MAX_ARTICLES).map((entry) => ({
35
+ id: entry.url,
36
+ date: formatDate(entry.published_at, "long"),
37
+ title: entry.title,
38
+ url: buildGarLink(entry.url, selectedSchool)
39
+ })), [data, selectedSchool, formatDate]), status = error ? "error" : isLoading ? "loading" : articles.length > 0 ? "default" : "empty";
40
+ return {
41
+ category,
42
+ setCategory,
43
+ articles,
44
+ status
45
+ };
46
+ }
47
+ export {
48
+ briefMeQueryOptions,
49
+ buildGarLink,
50
+ useBriefMe
51
+ };
@@ -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
+ };