@edifice.io/react 2.6.9-develop-integration.20261016090812 → 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 (145) 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 +1 -21
  6. package/dist/homepage.js +62 -24
  7. package/dist/hooks/index.d.ts +0 -3
  8. package/dist/hooks/useBackground/useBackground.d.ts +1 -1
  9. package/dist/hooks/useZendeskGuide/useZendeskGuide.d.ts +2 -6
  10. package/dist/hooks/useZendeskGuide/useZendeskGuide.js +11 -8
  11. package/dist/icons.js +404 -402
  12. package/dist/index.js +184 -198
  13. package/dist/modules/HelpZone/HelpZone.js +6 -8
  14. package/dist/modules/HelpZone/HelpZoneContainer.js +2 -5
  15. package/dist/modules/homepage/components/Agenda/Agenda.d.ts +10 -0
  16. package/dist/modules/homepage/components/Agenda/Agenda.js +54 -0
  17. package/dist/modules/homepage/components/Agenda/AgendaContainer.d.ts +1 -0
  18. package/dist/modules/homepage/components/Agenda/AgendaContainer.js +14 -0
  19. package/dist/modules/homepage/components/Agenda/AgendaEventCard.d.ts +10 -0
  20. package/dist/modules/homepage/components/Agenda/AgendaEventCard.js +30 -0
  21. package/dist/modules/homepage/components/Agenda/hooks/useAgendaContainer.d.ts +14 -0
  22. package/dist/modules/homepage/components/Agenda/hooks/useAgendaContainer.js +27 -0
  23. package/dist/modules/homepage/components/Agenda/index.d.ts +3 -0
  24. package/dist/modules/homepage/components/Agenda/services/api/agendaService.d.ts +24 -0
  25. package/dist/modules/homepage/components/Agenda/services/api/agendaService.js +45 -0
  26. package/dist/modules/homepage/components/Agenda/services/api/index.d.ts +4 -0
  27. package/dist/modules/homepage/components/Agenda/services/api/index.js +5 -0
  28. package/dist/modules/homepage/components/Agenda/services/queries/agenda.d.ts +19 -0
  29. package/dist/modules/homepage/components/Agenda/services/queries/agenda.js +26 -0
  30. package/dist/modules/homepage/components/BriefMe/BriefMe.d.ts +9 -0
  31. package/dist/modules/homepage/components/BriefMe/BriefMe.js +59 -0
  32. package/dist/modules/homepage/components/BriefMe/BriefMeContainer.d.ts +4 -0
  33. package/dist/modules/homepage/components/BriefMe/BriefMeContainer.js +17 -0
  34. package/dist/modules/homepage/components/BriefMe/index.d.ts +4 -0
  35. package/dist/modules/homepage/components/BriefMe/types.d.ts +17 -0
  36. package/dist/modules/homepage/components/BriefMe/types.js +8 -0
  37. package/dist/modules/homepage/components/BriefMe/useBriefMe.d.ts +31 -0
  38. package/dist/modules/homepage/components/BriefMe/useBriefMe.js +51 -0
  39. package/dist/modules/homepage/components/Cantine/Cantine.d.ts +7 -0
  40. package/dist/modules/homepage/components/Cantine/Cantine.js +44 -0
  41. package/dist/modules/homepage/components/Cantine/CantineContainer.d.ts +4 -0
  42. package/dist/modules/homepage/components/Cantine/CantineContainer.js +18 -0
  43. package/dist/modules/homepage/components/Cantine/CantineModal.d.ts +24 -0
  44. package/dist/modules/homepage/components/Cantine/CantineModal.js +88 -0
  45. package/dist/modules/homepage/components/Cantine/CantineModalContainer.d.ts +7 -0
  46. package/dist/modules/homepage/components/Cantine/CantineModalContainer.js +12 -0
  47. package/dist/modules/homepage/components/Cantine/components/CantineLegend.d.ts +5 -0
  48. package/dist/modules/homepage/components/Cantine/components/CantineLegend.js +22 -0
  49. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.d.ts +6 -0
  50. package/dist/modules/homepage/components/Cantine/components/CantineMenuSection.js +28 -0
  51. package/dist/modules/homepage/components/Cantine/components/cantineLabels.d.ts +12 -0
  52. package/dist/modules/homepage/components/Cantine/components/cantineLabels.js +60 -0
  53. package/dist/modules/homepage/components/Cantine/hooks/useCantine.d.ts +11 -0
  54. package/dist/modules/homepage/components/Cantine/hooks/useCantine.js +20 -0
  55. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.d.ts +24 -0
  56. package/dist/modules/homepage/components/Cantine/hooks/useCantineMenu.js +65 -0
  57. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.d.ts +23 -0
  58. package/dist/modules/homepage/components/Cantine/hooks/useCantineModal.js +43 -0
  59. package/dist/modules/homepage/components/Cantine/index.d.ts +7 -0
  60. package/dist/modules/homepage/components/Cantine/types.d.ts +42 -0
  61. package/dist/modules/homepage/components/Communities/Communities.js +4 -4
  62. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.d.ts +16 -0
  63. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.js +48 -0
  64. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.d.ts +4 -0
  65. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.js +12 -0
  66. package/dist/modules/homepage/components/GenerationHdf/formatSolde.d.ts +1 -0
  67. package/dist/modules/homepage/components/GenerationHdf/formatSolde.js +6 -0
  68. package/dist/modules/homepage/components/GenerationHdf/index.d.ts +3 -0
  69. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.d.ts +10 -0
  70. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.js +68 -0
  71. package/dist/modules/homepage/components/Header/Header.js +30 -21
  72. package/dist/modules/homepage/components/Header/MyAppsPopover.d.ts +5 -0
  73. package/dist/modules/homepage/components/Header/MyAppsPopover.js +28 -0
  74. package/dist/modules/homepage/components/Header/useSafeHoverPopover.js +32 -0
  75. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.d.ts +5 -1
  76. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.js +1 -1
  77. package/dist/modules/homepage/components/MessageFlashList/MessageFlash.js +1 -1
  78. package/dist/modules/homepage/components/Notifications/NotificationList.js +5 -5
  79. package/dist/modules/homepage/components/Notifications/NotificationSkeleton.js +2 -2
  80. package/dist/modules/homepage/components/Notifications/components/NotificationFilterMenu.js +1 -5
  81. package/dist/modules/homepage/components/Notifications/components/NotificationFilterModal.js +10 -12
  82. package/dist/modules/homepage/components/Notifications/components/NotificationOptionsMenu.js +3 -9
  83. package/dist/modules/homepage/components/Notifications/components/ReportNotificationModal.js +6 -12
  84. package/dist/modules/homepage/components/Notifications/components/notificationAdapter.js +12 -10
  85. package/dist/modules/homepage/components/Notifications/hooks/useNotificationList.js +9 -10
  86. package/dist/modules/homepage/components/Qwant/Qwant.d.ts +4 -0
  87. package/dist/modules/homepage/components/Qwant/Qwant.js +41 -0
  88. package/dist/modules/homepage/components/Qwant/QwantContainer.d.ts +1 -0
  89. package/dist/modules/homepage/components/Qwant/QwantContainer.js +10 -0
  90. package/dist/modules/homepage/components/Qwant/index.d.ts +3 -0
  91. package/dist/modules/homepage/components/SchoolSpace/SchoolSpaceContainer.js +1 -1
  92. package/dist/modules/homepage/components/Universalis/Universalis.d.ts +8 -0
  93. package/dist/modules/homepage/components/Universalis/Universalis.js +62 -0
  94. package/dist/modules/homepage/components/Universalis/UniversalisContainer.d.ts +1 -0
  95. package/dist/modules/homepage/components/Universalis/UniversalisContainer.js +16 -0
  96. package/dist/modules/homepage/components/Universalis/index.d.ts +3 -0
  97. package/dist/modules/homepage/components/UserSpace/UserSpace.d.ts +3 -1
  98. package/dist/modules/homepage/components/UserSpace/UserSpace.js +13 -7
  99. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.d.ts +4 -2
  100. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.js +3 -2
  101. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.d.ts +16 -0
  102. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.js +15 -0
  103. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.d.ts +21 -0
  104. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.js +47 -0
  105. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/index.d.ts +2 -0
  106. package/dist/modules/homepage/components/index.d.ts +8 -1
  107. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.d.ts +2 -2
  108. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.js +4 -4
  109. package/dist/modules/icons/components/IconAddWidget.d.ts +7 -0
  110. package/dist/modules/icons/components/IconAddWidget.js +12 -0
  111. package/dist/modules/icons/components/index.d.ts +1 -0
  112. package/dist/modules/multimedia/FileCard/index.d.ts +0 -4
  113. package/dist/modules/multimedia/Linker/InternalLinker/InternalLinker.d.ts +1 -7
  114. package/dist/modules/multimedia/Linker/InternalLinker/InternalLinker.js +0 -2
  115. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.d.ts +2 -2
  116. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.js +12 -48
  117. package/dist/modules/multimedia/MediaLibrary/innertabs/index.d.ts +0 -2
  118. package/dist/modules/multimedia/MediaLibrary/innertabs/index.js +0 -4
  119. package/dist/modules/multimedia/Workspace/Workspace.js +5 -8
  120. package/dist/modules/multimedia/index.d.ts +0 -2
  121. package/dist/multimedia.js +18 -26
  122. package/package.json +6 -6
  123. package/dist/hooks/useCarbonioUnread/index.d.ts +0 -1
  124. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.d.ts +0 -5
  125. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.js +0 -24
  126. package/dist/hooks/useGoogleDriveSearch/index.d.ts +0 -1
  127. package/dist/hooks/useGoogleDriveSearch/useGoogleDriveSearch.d.ts +0 -19
  128. package/dist/hooks/useGoogleDriveSearch/useGoogleDriveSearch.js +0 -60
  129. package/dist/hooks/useNextcloudSearch/index.d.ts +0 -1
  130. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.d.ts +0 -14
  131. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.js +0 -64
  132. package/dist/modules/multimedia/FileCard/GoogleDriveFileCard.d.ts +0 -25
  133. package/dist/modules/multimedia/FileCard/GoogleDriveFileCard.js +0 -102
  134. package/dist/modules/multimedia/FileCard/NextcloudFileCard.d.ts +0 -25
  135. package/dist/modules/multimedia/FileCard/NextcloudFileCard.js +0 -102
  136. package/dist/modules/multimedia/GoogleDrive/GoogleDrive.d.ts +0 -24
  137. package/dist/modules/multimedia/GoogleDrive/GoogleDrive.js +0 -103
  138. package/dist/modules/multimedia/GoogleDrive/index.d.ts +0 -2
  139. package/dist/modules/multimedia/MediaLibrary/innertabs/GoogleDrive.d.ts +0 -1
  140. package/dist/modules/multimedia/MediaLibrary/innertabs/GoogleDrive.js +0 -61
  141. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.d.ts +0 -1
  142. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.js +0 -48
  143. package/dist/modules/multimedia/Nextcloud/Nextcloud.d.ts +0 -24
  144. package/dist/modules/multimedia/Nextcloud/Nextcloud.js +0 -120
  145. package/dist/modules/multimedia/Nextcloud/index.d.ts +0 -2
@@ -0,0 +1,30 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import SvgIconClock from "../../../icons/components/IconClock.js";
4
+ import useDate from "../../../../hooks/useDate/useDate.js";
5
+ import Flex from "../../../../components/Flex/Flex.js";
6
+ const capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1), AgendaEventCard = ({
7
+ event,
8
+ onClick
9
+ }) => {
10
+ const {
11
+ t
12
+ } = useTranslation(), {
13
+ formatDate,
14
+ dateIsSame
15
+ } = useDate(), formatTime = (date) => formatDate(date, "HH[h]mm"), timeLabel = event.allDay ? t("homepage.agenda.allDay") : dateIsSame(event.startMoment, event.endMoment, "day") ? `${formatTime(event.startMoment)} - ${formatTime(event.endMoment)}` : t("homepage.agenda.multiDayTime", {
16
+ startTime: formatTime(event.startMoment),
17
+ endDay: capitalize(formatDate(event.endMoment, "ddd D")),
18
+ endTime: formatTime(event.endMoment)
19
+ });
20
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "agenda-event-card", onClick, "data-testid": "agenda-event-card", children: [
21
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "8", className: "agenda-event-card-time", children: [
22
+ /* @__PURE__ */ jsx(SvgIconClock, { width: "20", height: "20" }),
23
+ /* @__PURE__ */ jsx("span", { children: timeLabel })
24
+ ] }),
25
+ /* @__PURE__ */ jsx("p", { className: "agenda-event-card-title", children: event.title })
26
+ ] });
27
+ };
28
+ export {
29
+ AgendaEventCard
30
+ };
@@ -0,0 +1,14 @@
1
+ import { CalendarEvent } from '@edifice.io/client';
2
+ /** Number of upcoming events shown by the widget. */
3
+ export declare const MAX_VISIBLE_EVENTS = 3;
4
+ export interface UseAgendaContainerReturn {
5
+ events: CalendarEvent[];
6
+ isLoading: boolean;
7
+ error: Error | null;
8
+ }
9
+ /**
10
+ * Loads the current user's calendars, then their events, and keeps only the
11
+ * next `MAX_VISIBLE_EVENTS` events that haven't fully elapsed yet — an event
12
+ * still in progress (end date in the future) counts as "upcoming" too.
13
+ */
14
+ export declare const useAgendaContainer: () => UseAgendaContainerReturn;
@@ -0,0 +1,27 @@
1
+ import dayjs from "dayjs";
2
+ import { useMemo } from "react";
3
+ import { useCalendars, useEvents } from "../services/queries/agenda.js";
4
+ const MAX_VISIBLE_EVENTS = 3, useAgendaContainer = () => {
5
+ const {
6
+ data: calendars,
7
+ isLoading: isLoadingCalendars,
8
+ error: calendarsError
9
+ } = useCalendars(), calendarIds = useMemo(() => (calendars == null ? void 0 : calendars.map((calendar) => calendar.id)) ?? [], [calendars]), {
10
+ data: rawEvents,
11
+ isLoading: isLoadingEvents,
12
+ error: eventsError
13
+ } = useEvents(calendarIds, MAX_VISIBLE_EVENTS);
14
+ return {
15
+ events: useMemo(() => {
16
+ if (!rawEvents) return [];
17
+ const now = dayjs();
18
+ return rawEvents.filter((event) => dayjs(event.endMoment).isAfter(now)).sort((a, b) => dayjs(a.startMoment).diff(dayjs(b.startMoment))).slice(0, MAX_VISIBLE_EVENTS);
19
+ }, [rawEvents]),
20
+ isLoading: isLoadingCalendars || isLoadingEvents,
21
+ error: calendarsError ?? eventsError
22
+ };
23
+ };
24
+ export {
25
+ MAX_VISIBLE_EVENTS,
26
+ useAgendaContainer
27
+ };
@@ -0,0 +1,3 @@
1
+ export * from './Agenda';
2
+ export * from './AgendaContainer';
3
+ export * from './AgendaEventCard';
@@ -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
+ }