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

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 (123) 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 +54 -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/Communities/Communities.js +4 -4
  40. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.d.ts +16 -0
  41. package/dist/modules/homepage/components/GenerationHdf/GenerationHdf.js +48 -0
  42. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.d.ts +4 -0
  43. package/dist/modules/homepage/components/GenerationHdf/GenerationHdfContainer.js +12 -0
  44. package/dist/modules/homepage/components/GenerationHdf/formatSolde.d.ts +1 -0
  45. package/dist/modules/homepage/components/GenerationHdf/formatSolde.js +6 -0
  46. package/dist/modules/homepage/components/GenerationHdf/index.d.ts +3 -0
  47. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.d.ts +10 -0
  48. package/dist/modules/homepage/components/GenerationHdf/useGenerationHdf.js +68 -0
  49. package/dist/modules/homepage/components/Header/Header.js +30 -21
  50. package/dist/modules/homepage/components/Header/MyAppsPopover.d.ts +5 -0
  51. package/dist/modules/homepage/components/Header/MyAppsPopover.js +28 -0
  52. package/dist/modules/homepage/components/Header/useSafeHoverPopover.js +32 -0
  53. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.d.ts +5 -1
  54. package/dist/modules/homepage/components/HomeCard/HomeCardHeader.js +1 -1
  55. package/dist/modules/homepage/components/MessageFlashList/MessageFlash.js +1 -1
  56. package/dist/modules/homepage/components/Notifications/NotificationList.js +5 -5
  57. package/dist/modules/homepage/components/Notifications/NotificationSkeleton.js +2 -2
  58. package/dist/modules/homepage/components/Notifications/components/NotificationFilterMenu.js +1 -5
  59. package/dist/modules/homepage/components/Notifications/components/NotificationFilterModal.js +10 -12
  60. package/dist/modules/homepage/components/Notifications/components/NotificationOptionsMenu.js +3 -9
  61. package/dist/modules/homepage/components/Notifications/components/ReportNotificationModal.js +6 -12
  62. package/dist/modules/homepage/components/Notifications/components/notificationAdapter.js +12 -10
  63. package/dist/modules/homepage/components/Notifications/hooks/useNotificationList.js +9 -10
  64. package/dist/modules/homepage/components/Qwant/Qwant.d.ts +4 -0
  65. package/dist/modules/homepage/components/Qwant/Qwant.js +41 -0
  66. package/dist/modules/homepage/components/Qwant/QwantContainer.d.ts +1 -0
  67. package/dist/modules/homepage/components/Qwant/QwantContainer.js +10 -0
  68. package/dist/modules/homepage/components/Qwant/index.d.ts +3 -0
  69. package/dist/modules/homepage/components/SchoolSpace/SchoolSpaceContainer.js +1 -1
  70. package/dist/modules/homepage/components/Universalis/Universalis.d.ts +8 -0
  71. package/dist/modules/homepage/components/Universalis/Universalis.js +62 -0
  72. package/dist/modules/homepage/components/Universalis/UniversalisContainer.d.ts +1 -0
  73. package/dist/modules/homepage/components/Universalis/UniversalisContainer.js +16 -0
  74. package/dist/modules/homepage/components/Universalis/index.d.ts +3 -0
  75. package/dist/modules/homepage/components/UserSpace/UserSpace.d.ts +3 -1
  76. package/dist/modules/homepage/components/UserSpace/UserSpace.js +13 -7
  77. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.d.ts +4 -2
  78. package/dist/modules/homepage/components/UserSpace/UserSpaceContainer.js +3 -2
  79. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.d.ts +16 -0
  80. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetToggle.js +15 -0
  81. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.d.ts +21 -0
  82. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/WidgetsPersonalizationPanel.js +47 -0
  83. package/dist/modules/homepage/components/WidgetsPersonalizationPanel/index.d.ts +2 -0
  84. package/dist/modules/homepage/components/index.d.ts +7 -1
  85. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.d.ts +2 -2
  86. package/dist/modules/homepage/{components/SchoolSpace → hooks}/useUserSchools.js +4 -4
  87. package/dist/modules/icons/components/IconAddWidget.d.ts +7 -0
  88. package/dist/modules/icons/components/IconAddWidget.js +12 -0
  89. package/dist/modules/icons/components/index.d.ts +1 -0
  90. package/dist/modules/multimedia/FileCard/index.d.ts +0 -4
  91. package/dist/modules/multimedia/Linker/InternalLinker/InternalLinker.d.ts +1 -7
  92. package/dist/modules/multimedia/Linker/InternalLinker/InternalLinker.js +0 -2
  93. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.d.ts +2 -2
  94. package/dist/modules/multimedia/MediaLibrary/MediaLibrary.js +12 -48
  95. package/dist/modules/multimedia/MediaLibrary/innertabs/index.d.ts +0 -2
  96. package/dist/modules/multimedia/MediaLibrary/innertabs/index.js +0 -4
  97. package/dist/modules/multimedia/Workspace/Workspace.js +5 -8
  98. package/dist/modules/multimedia/index.d.ts +0 -2
  99. package/dist/multimedia.js +18 -26
  100. package/package.json +6 -6
  101. package/dist/hooks/useCarbonioUnread/index.d.ts +0 -1
  102. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.d.ts +0 -5
  103. package/dist/hooks/useCarbonioUnread/useCarbonioUnread.js +0 -24
  104. package/dist/hooks/useGoogleDriveSearch/index.d.ts +0 -1
  105. package/dist/hooks/useGoogleDriveSearch/useGoogleDriveSearch.d.ts +0 -19
  106. package/dist/hooks/useGoogleDriveSearch/useGoogleDriveSearch.js +0 -60
  107. package/dist/hooks/useNextcloudSearch/index.d.ts +0 -1
  108. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.d.ts +0 -14
  109. package/dist/hooks/useNextcloudSearch/useNextcloudSearch.js +0 -64
  110. package/dist/modules/multimedia/FileCard/GoogleDriveFileCard.d.ts +0 -25
  111. package/dist/modules/multimedia/FileCard/GoogleDriveFileCard.js +0 -102
  112. package/dist/modules/multimedia/FileCard/NextcloudFileCard.d.ts +0 -25
  113. package/dist/modules/multimedia/FileCard/NextcloudFileCard.js +0 -102
  114. package/dist/modules/multimedia/GoogleDrive/GoogleDrive.d.ts +0 -24
  115. package/dist/modules/multimedia/GoogleDrive/GoogleDrive.js +0 -103
  116. package/dist/modules/multimedia/GoogleDrive/index.d.ts +0 -2
  117. package/dist/modules/multimedia/MediaLibrary/innertabs/GoogleDrive.d.ts +0 -1
  118. package/dist/modules/multimedia/MediaLibrary/innertabs/GoogleDrive.js +0 -61
  119. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.d.ts +0 -1
  120. package/dist/modules/multimedia/MediaLibrary/innertabs/Nextcloud.js +0 -48
  121. package/dist/modules/multimedia/Nextcloud/Nextcloud.d.ts +0 -24
  122. package/dist/modules/multimedia/Nextcloud/Nextcloud.js +0 -124
  123. 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
+ };
@@ -22,11 +22,11 @@ const Communities = ({
22
22
  height: 80
23
23
  } }),
24
24
  /* @__PURE__ */ jsx("div", { className: "communities-empty-content", children: canCreateCommunity ? /* @__PURE__ */ jsxs(Fragment, { children: [
25
- /* @__PURE__ */ jsx("p", { className: "communities-empty-title", children: t("homepage.communities.subtitle.teacher", "Réunissez vos élèves avec Communautés !") }),
26
- /* @__PURE__ */ jsx("p", { className: "communities-empty-description", children: t("homepage.communities.description.teacher", "Centralisez et organisez les documents et les ressources pour vos groupes d'élèves.") })
25
+ /* @__PURE__ */ jsx("p", { className: "communities-empty-title", children: t("homepage.communities.subtitle.teacher") }),
26
+ /* @__PURE__ */ jsx("p", { className: "communities-empty-description", children: t("homepage.communities.description.teacher") })
27
27
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
28
- /* @__PURE__ */ jsx("p", { className: "communities-empty-title", children: t("homepage.communities.subtitle.student", "Retrouvez toutes vos communautés ici ! ") }),
29
- /* @__PURE__ */ jsx("p", { className: "communities-empty-description", children: t("homepage.communities.description.student", `Consultez l'onglet "Nouveaux partages" pour découvrir si vous avez été ajouté à une nouvelle communauté.`) })
28
+ /* @__PURE__ */ jsx("p", { className: "communities-empty-title", children: t("homepage.communities.subtitle.student") }),
29
+ /* @__PURE__ */ jsx("p", { className: "communities-empty-description", children: t("homepage.communities.description.student") })
30
30
  ] }) })
31
31
  ] }) }) })
32
32
  ] });
@@ -0,0 +1,16 @@
1
+ import { FormEvent } from 'react';
2
+ export type GenerationHdfStatus = 'idle' | 'loading' | 'error' | 'account';
3
+ export interface GenerationHdfWallet {
4
+ label: string;
5
+ amount: string;
6
+ }
7
+ export interface GenerationHdfProps {
8
+ handleActionClick: () => void;
9
+ status: GenerationHdfStatus;
10
+ cardNumber: string;
11
+ onCardNumberChange: (value: string) => void;
12
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
13
+ onEdit: () => void;
14
+ wallets: GenerationHdfWallet[];
15
+ }
16
+ export default function GenerationHdf({ handleActionClick, status, cardNumber, onCardNumberChange, onSubmit, onEdit, wallets, }: GenerationHdfProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,48 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import illuGenerationHdf from "@edifice.io/bootstrap/dist/images/homepage/illu-generation-hdf.svg";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconExternalLink from "../../../icons/components/IconExternalLink.js";
5
+ import HomeCard from "../HomeCard/HomeCard.js";
6
+ import ButtonBeta from "../../../../components/ButtonBeta/ButtonBeta.js";
7
+ import Image from "../../../../components/Image/Image.js";
8
+ import FormControl from "../../../../components/Form/FormControl.js";
9
+ import Input from "../../../../components/Input/Input.js";
10
+ function GenerationHdf({
11
+ handleActionClick,
12
+ status,
13
+ cardNumber,
14
+ onCardNumberChange,
15
+ onSubmit,
16
+ onEdit,
17
+ wallets
18
+ }) {
19
+ const {
20
+ t
21
+ } = useTranslation(), isAccount = status === "account", isLoading = status === "loading", isError = status === "error";
22
+ return /* @__PURE__ */ jsxs(HomeCard, { variant: "primary", children: [
23
+ /* @__PURE__ */ jsxs("div", { className: "generation-hdf__header", children: [
24
+ /* @__PURE__ */ jsx("h3", { className: "generation-hdf__title", children: t("homepage.widget.generation-hdf.title") }),
25
+ /* @__PURE__ */ jsx(ButtonBeta, { "data-testid": "generation-hdf-button-open", "aria-label": t("homepage.widget.generation-hdf.open"), onClick: handleActionClick, leftIcon: /* @__PURE__ */ jsx(SvgIconExternalLink, {}), variant: "ghost", color: "tertiary" })
26
+ ] }),
27
+ /* @__PURE__ */ jsx(HomeCard.Content, { children: /* @__PURE__ */ jsxs("div", { className: "generation-hdf", children: [
28
+ /* @__PURE__ */ jsx(Image, { src: illuGenerationHdf, alt: "Génération #HDF", className: "generation-hdf__logo" }),
29
+ isAccount ? /* @__PURE__ */ jsxs("div", { className: "generation-hdf__account", children: [
30
+ /* @__PURE__ */ jsx("h4", { className: "generation-hdf__account-title", children: t("homepage.widget.generation-hdf.wallets-title") }),
31
+ /* @__PURE__ */ jsx("ul", { className: "generation-hdf__wallets", children: wallets.map((wallet, index) => /* @__PURE__ */ jsxs("li", { className: "generation-hdf__wallet", children: [
32
+ /* @__PURE__ */ jsx("span", { className: "generation-hdf__wallet-label", children: wallet.label }),
33
+ /* @__PURE__ */ jsx("span", { className: "generation-hdf__wallet-amount", children: wallet.amount })
34
+ ] }, index)) })
35
+ ] }) : /* @__PURE__ */ jsx("p", { className: "generation-hdf__description", children: t("homepage.widget.generation-hdf.description") }),
36
+ /* @__PURE__ */ jsxs("form", { className: "generation-hdf__form", onSubmit, children: [
37
+ /* @__PURE__ */ jsxs(FormControl, { id: "generationHdfCardNumber", className: "generation-hdf__field", status: isError ? "invalid" : void 0, children: [
38
+ /* @__PURE__ */ jsx(Input, { size: "md", type: "text", inputMode: "numeric", placeholder: t("homepage.widget.generation-hdf.placeholder"), value: cardNumber, onChange: (event) => onCardNumberChange(event.target.value), disabled: isAccount, maxLength: 50 }),
39
+ isError && /* @__PURE__ */ jsx(FormControl.Text, { children: t("homepage.widget.generation-hdf.error") })
40
+ ] }),
41
+ isAccount ? /* @__PURE__ */ jsx(ButtonBeta, { type: "button", variant: "outline", color: "default", onClick: onEdit, children: t("homepage.widget.generation-hdf.edit") }) : /* @__PURE__ */ jsx(ButtonBeta, { type: "submit", variant: "outline", color: "default", isLoading, disabled: !cardNumber.trim(), children: t("homepage.widget.generation-hdf.submit") })
42
+ ] })
43
+ ] }) })
44
+ ] });
45
+ }
46
+ export {
47
+ GenerationHdf as default
48
+ };
@@ -0,0 +1,4 @@
1
+ export declare function GenerationHdfContainer(): import("react/jsx-runtime").JSX.Element;
2
+ export declare namespace GenerationHdfContainer {
3
+ var displayName: string;
4
+ }
@@ -0,0 +1,12 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import GenerationHdf from "./GenerationHdf.js";
3
+ import { useGenerationHdf } from "./useGenerationHdf.js";
4
+ function GenerationHdfContainer() {
5
+ const generationHdf = useGenerationHdf();
6
+ return /* @__PURE__ */ jsx(GenerationHdf, { handleActionClick: () => {
7
+ window.open("https://generation.hautsdefrance.fr", "_blank", "noopener,noreferrer");
8
+ }, ...generationHdf });
9
+ }
10
+ export {
11
+ GenerationHdfContainer
12
+ };
@@ -0,0 +1 @@
1
+ export declare function formatSolde(soldeStr: string): string;
@@ -0,0 +1,6 @@
1
+ function formatSolde(soldeStr) {
2
+ return typeof soldeStr != "string" || soldeStr.length === 0 ? soldeStr : soldeStr.length === 1 ? `0,0${soldeStr}` : soldeStr.length === 2 ? `0,${soldeStr}` : `${soldeStr.substring(0, soldeStr.length - 2)},${soldeStr.substring(soldeStr.length - 2)}`;
3
+ }
4
+ export {
5
+ formatSolde
6
+ };
@@ -0,0 +1,3 @@
1
+ export * from './GenerationHdf';
2
+ export { default as GenerationHdf } from './GenerationHdf';
3
+ export * from './GenerationHdfContainer';
@@ -0,0 +1,10 @@
1
+ import { FormEvent } from 'react';
2
+ import { GenerationHdfStatus, GenerationHdfWallet } from './GenerationHdf';
3
+ export declare function useGenerationHdf(): {
4
+ status: GenerationHdfStatus;
5
+ cardNumber: string;
6
+ onCardNumberChange: import('react').Dispatch<import('react').SetStateAction<string>>;
7
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
8
+ onEdit: () => void;
9
+ wallets: GenerationHdfWallet[];
10
+ };
@@ -0,0 +1,68 @@
1
+ import { odeServices, USER_PREFS } from "@edifice.io/client";
2
+ import { useQuery, useMutation } from "@tanstack/react-query";
3
+ import { useState, useRef, useEffect } from "react";
4
+ import { formatSolde } from "./formatSolde.js";
5
+ function mapSalesToWallets(data) {
6
+ return (data.sales ?? []).map((sale) => {
7
+ var _a;
8
+ const wallet = (_a = data.wallets) == null ? void 0 : _a.find((w) => w.code === sale.numPM);
9
+ return {
10
+ label: (wallet == null ? void 0 : wallet.libelle) ?? "",
11
+ amount: `${formatSolde(sale.solde)} €`
12
+ };
13
+ });
14
+ }
15
+ async function fetchSales(cardNb) {
16
+ const http = odeServices.http(), data = await http.get("/cursus/sales", {
17
+ queryParams: {
18
+ cardNb
19
+ }
20
+ });
21
+ if (http.isResponseError())
22
+ throw new Error(http.latestResponse.statusText);
23
+ return data;
24
+ }
25
+ function useGenerationHdf() {
26
+ const [cardNumber, setCardNumber] = useState(""), autoLoadTriggered = useRef(!1), preferenceQuery = useQuery({
27
+ queryKey: ["cursus", "preference"],
28
+ queryFn: () => odeServices.conf().getPreference(USER_PREFS.CURSUS)
29
+ }), salesMutation = useMutation({
30
+ mutationFn: async ({
31
+ cardNb,
32
+ persist
33
+ }) => {
34
+ const data = await fetchSales(cardNb);
35
+ return persist && await odeServices.conf().savePreference(USER_PREFS.CURSUS, {
36
+ cardNb
37
+ }), data;
38
+ }
39
+ });
40
+ useEffect(() => {
41
+ if (autoLoadTriggered.current || !preferenceQuery.data) return;
42
+ autoLoadTriggered.current = !0;
43
+ const storedCardNb = preferenceQuery.data.cardNb;
44
+ storedCardNb && (setCardNumber(storedCardNb), salesMutation.mutate({
45
+ cardNb: storedCardNb,
46
+ persist: !1
47
+ }));
48
+ }, [preferenceQuery.data, salesMutation]);
49
+ const status = preferenceQuery.data ? salesMutation.isPending ? "loading" : salesMutation.isError ? "error" : salesMutation.isSuccess ? "account" : "idle" : "loading", wallets = salesMutation.data ? mapSalesToWallets(salesMutation.data) : [];
50
+ return {
51
+ status,
52
+ cardNumber,
53
+ onCardNumberChange: setCardNumber,
54
+ onSubmit: (event) => {
55
+ event.preventDefault(), !salesMutation.isPending && salesMutation.mutate({
56
+ cardNb: cardNumber,
57
+ persist: !0
58
+ });
59
+ },
60
+ onEdit: () => {
61
+ odeServices.conf().savePreference(USER_PREFS.CURSUS, {}), setCardNumber(""), salesMutation.reset();
62
+ },
63
+ wallets
64
+ };
65
+ }
66
+ export {
67
+ useGenerationHdf
68
+ };