@edifice.io/react 2.6.2 → 2.6.3-develop-enabling.20260825190837
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Alert/Alert.js +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +5 -0
- package/dist/components/DatePicker/DatePicker.js +2 -0
- package/dist/components/Layout/Layout.js +5 -3
- package/dist/components/Layout/components/NavLink.d.ts +1 -1
- package/dist/components/Layout/components/NavLink.js +2 -0
- package/dist/hooks/useClickOutside/useClickOutside.d.ts +1 -1
- package/dist/hooks/useClickOutside/useClickOutside.js +1 -1
- package/dist/icons-apps.js +112 -100
- package/dist/icons.js +340 -338
- package/dist/modules/editor/test-utils/createTestEditor.d.ts +10 -0
- package/dist/modules/homepage/components/Communities/Communities.d.ts +10 -0
- package/dist/modules/homepage/components/Communities/CommunitiesContainer.d.ts +9 -0
- package/dist/modules/homepage/components/Communities/CommunitiesSkeleton.d.ts +5 -0
- package/dist/modules/homepage/components/Communities/CommunityItem.d.ts +11 -0
- package/dist/modules/homepage/components/Communities/index.d.ts +8 -0
- package/dist/modules/homepage/components/Communities/useCommunities.d.ts +13 -0
- package/dist/modules/homepage/components/Favorites/Favorites.js +7 -4
- package/dist/modules/homepage/components/Header/Header.js +20 -2
- package/dist/modules/homepage/components/HomeCard/HomeCard.d.ts +5 -1
- package/dist/modules/homepage/components/HomeCard/HomeCard.js +10 -2
- package/dist/modules/homepage/components/LastInfos/LastInfosList.js +2 -2
- package/dist/modules/homepage/components/Notifications/NotificationItem.js +5 -4
- package/dist/modules/homepage/components/Notifications/NotificationList.d.ts +7 -1
- package/dist/modules/homepage/components/Notifications/NotificationList.js +10 -3
- package/dist/modules/homepage/components/Notifications/NotificationListContainer.js +4 -1
- package/dist/modules/homepage/components/Notifications/components/CommonNotificationItem.d.ts +2 -1
- package/dist/modules/homepage/components/Notifications/components/CommonNotificationItem.js +14 -10
- package/dist/modules/homepage/components/Notifications/components/NotificationFilterMenu.d.ts +16 -0
- package/dist/modules/homepage/components/Notifications/components/NotificationFilterMenu.js +29 -0
- package/dist/modules/homepage/components/Notifications/components/NotificationFilterModal.d.ts +18 -0
- package/dist/modules/homepage/components/Notifications/components/NotificationFilterModal.js +67 -0
- package/dist/modules/homepage/components/Notifications/components/NotificationItemResource.d.ts +2 -1
- package/dist/modules/homepage/components/Notifications/components/NotificationItemResource.js +3 -2
- package/dist/modules/homepage/components/Notifications/components/NotificationOptionsMenu.d.ts +12 -0
- package/dist/modules/homepage/components/Notifications/components/NotificationOptionsMenu.js +42 -0
- package/dist/modules/homepage/components/Notifications/components/ReportNotificationModal.d.ts +13 -0
- package/dist/modules/homepage/components/Notifications/components/ReportNotificationModal.js +31 -0
- package/dist/modules/homepage/components/Notifications/components/SystemNotificationItem.d.ts +3 -1
- package/dist/modules/homepage/components/Notifications/components/SystemNotificationItem.js +3 -2
- package/dist/modules/homepage/components/Notifications/components/UserNotificationItem.d.ts +3 -1
- package/dist/modules/homepage/components/Notifications/components/UserNotificationItem.js +3 -2
- package/dist/modules/homepage/components/Notifications/components/notificationAdapter.d.ts +22 -7
- package/dist/modules/homepage/components/Notifications/components/notificationAdapter.js +31 -13
- package/dist/modules/homepage/components/Notifications/hooks/useNotificationList.d.ts +11 -1
- package/dist/modules/homepage/components/Notifications/hooks/useNotificationList.js +34 -2
- package/dist/modules/homepage/components/Notifications/services/api/index.d.ts +2 -0
- package/dist/modules/homepage/components/Notifications/services/api/notificationService.d.ts +8 -0
- package/dist/modules/homepage/components/Notifications/services/api/notificationService.js +12 -0
- package/dist/modules/homepage/components/Notifications/services/queries/notification.d.ts +13 -1
- package/dist/modules/homepage/components/Notifications/services/queries/notification.js +41 -4
- package/dist/modules/homepage/components/SchoolSpace/SchoolSpace.js +20 -11
- package/dist/modules/homepage/components/UserSpace/UserSpace.js +5 -2
- package/dist/modules/homepage/components/UserSpace/hooks/useChildren.d.ts +14 -0
- package/dist/modules/homepage/components/UserSpace/hooks/useChildren.js +23 -0
- package/dist/modules/homepage/components/UserSpace/hooks/useProfileLinks.d.ts +8 -0
- package/dist/modules/homepage/components/UserSpace/hooks/useProfileLinks.js +65 -0
- package/dist/modules/icons/components/IconClass.d.ts +7 -0
- package/dist/modules/icons/components/IconClass.js +13 -0
- package/dist/modules/icons/components/apps/IconNextcloudDeck.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconNextcloudDeck.js +12 -0
- package/dist/modules/icons/components/apps/IconNextcloudFiles.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconNextcloudFiles.js +12 -0
- package/dist/modules/icons/components/apps/IconNextcloudForms.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconNextcloudForms.js +12 -0
- package/dist/modules/icons/components/apps/IconNextcloudNotes.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconNextcloudNotes.js +12 -0
- package/dist/modules/icons/components/apps/IconNextcloudTalk.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconNextcloudTalk.js +12 -0
- package/dist/modules/icons/components/apps/IconPeertube.d.ts +7 -0
- package/dist/modules/icons/components/apps/IconPeertube.js +21 -0
- package/dist/modules/icons/components/apps/index.d.ts +6 -0
- package/dist/modules/icons/components/index.d.ts +1 -0
- package/dist/modules/multimedia/testing/mediaHarness.d.ts +154 -0
- package/package.json +6 -6
- package/dist/modules/multimedia/LinkerCard/LinkerCard._.d.ts +0 -8
- package/dist/modules/multimedia/UploadCard/UploadCard._.d.ts +0 -9
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import SvgIconAlertTriangle from "../../../../icons/components/IconAlertTriangle.js";
|
|
4
|
+
import Modal from "../../../../../components/Modal/Modal.js";
|
|
5
|
+
import ButtonBeta from "../../../../../components/ButtonBeta/ButtonBeta.js";
|
|
6
|
+
const ReportNotificationModal = ({
|
|
7
|
+
isOpen,
|
|
8
|
+
onCancel,
|
|
9
|
+
onConfirm
|
|
10
|
+
}) => {
|
|
11
|
+
const {
|
|
12
|
+
t
|
|
13
|
+
} = useTranslation();
|
|
14
|
+
return /* @__PURE__ */ jsxs(Modal, { id: "report-notification-modal", size: "lg", isOpen, onModalClose: onCancel, children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Modal.Header, { onModalClose: onCancel, children: t("homepage.notifications.report-modal.title", {
|
|
16
|
+
defaultValue: "Signaler une notification"
|
|
17
|
+
}) }),
|
|
18
|
+
/* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx("p", { children: t("homepage.notifications.report-modal.body", {
|
|
19
|
+
defaultValue: "Attention ! Vous souhaitez signaler une notification inappropriée ou qui ne respecte pas les conditions d'utilisation de ONE. L'heure et l'origine de ce signalement seront enregistrées et transmises à un administrateur pour traitement."
|
|
20
|
+
}) }) }),
|
|
21
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
|
22
|
+
/* @__PURE__ */ jsx(ButtonBeta, { color: "tertiary", onClick: onCancel, type: "button", variant: "ghost", children: t("cancel") }),
|
|
23
|
+
/* @__PURE__ */ jsx(ButtonBeta, { color: "default", onClick: onConfirm, type: "button", variant: "filled", leftIcon: /* @__PURE__ */ jsx(SvgIconAlertTriangle, {}), children: t("homepage.notifications.report-modal.confirm", {
|
|
24
|
+
defaultValue: "Signaler la notification"
|
|
25
|
+
}) })
|
|
26
|
+
] })
|
|
27
|
+
] });
|
|
28
|
+
};
|
|
29
|
+
export {
|
|
30
|
+
ReportNotificationModal as default
|
|
31
|
+
};
|
package/dist/modules/homepage/components/Notifications/components/SystemNotificationItem.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
1
2
|
import { SystemWebNotification } from './notificationAdapter';
|
|
2
3
|
export type SystemNotificationItemProps = {
|
|
3
4
|
notification: SystemWebNotification;
|
|
5
|
+
menu?: ReactNode;
|
|
4
6
|
};
|
|
5
7
|
/**
|
|
6
8
|
* Renders a system notification (no sender) using an app icon as the picture.
|
|
@@ -9,7 +11,7 @@ export type SystemNotificationItemProps = {
|
|
|
9
11
|
* rather than this component directly.
|
|
10
12
|
*/
|
|
11
13
|
declare const SystemNotificationItem: {
|
|
12
|
-
({ notification, }: SystemNotificationItemProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
({ notification, menu, }: SystemNotificationItemProps): import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
displayName: string;
|
|
14
16
|
};
|
|
15
17
|
export default SystemNotificationItem;
|
|
@@ -3,7 +3,8 @@ import { useTranslation } from "react-i18next";
|
|
|
3
3
|
import CommonNotificationItem from "./CommonNotificationItem.js";
|
|
4
4
|
import AppIcon from "../../../../../components/AppIcon/AppIcon.js";
|
|
5
5
|
const SystemNotificationItem = ({
|
|
6
|
-
notification
|
|
6
|
+
notification,
|
|
7
|
+
menu
|
|
7
8
|
}) => {
|
|
8
9
|
const {
|
|
9
10
|
params,
|
|
@@ -13,7 +14,7 @@ const SystemNotificationItem = ({
|
|
|
13
14
|
} = notification, {
|
|
14
15
|
t
|
|
15
16
|
} = useTranslation(), appName = t(params.appCode);
|
|
16
|
-
return /* @__PURE__ */ jsx(CommonNotificationItem, { uri, message, date, picture: /* @__PURE__ */ jsx("a", { href: uri, title: appName, "data-testid": "notification-item-app-icon", "aria-label": t("homepage.notifications.app-icon.placeholder"), children: /* @__PURE__ */ jsx(AppIcon, { app: params.appCode, size: "24", variant: "square", className: "notification-item-app-icon" }) }) });
|
|
17
|
+
return /* @__PURE__ */ jsx(CommonNotificationItem, { uri, message, date, menu, picture: /* @__PURE__ */ jsx("a", { href: uri, title: appName, "data-testid": "notification-item-app-icon", "aria-label": t("homepage.notifications.app-icon.placeholder"), children: /* @__PURE__ */ jsx(AppIcon, { app: params.appCode, size: "24", variant: "square", className: "notification-item-app-icon" }) }) });
|
|
17
18
|
};
|
|
18
19
|
export {
|
|
19
20
|
SystemNotificationItem as default
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
1
2
|
import { UserWebNotification } from './notificationAdapter';
|
|
2
3
|
export type UserNotificationItemProps = {
|
|
3
4
|
notification: UserWebNotification;
|
|
5
|
+
menu?: ReactNode;
|
|
4
6
|
};
|
|
5
7
|
/**
|
|
6
8
|
* Renders a user-triggered notification using the sender's avatar as the picture.
|
|
@@ -9,7 +11,7 @@ export type UserNotificationItemProps = {
|
|
|
9
11
|
* — prefer using `Notification` at the top level rather than this component directly.
|
|
10
12
|
*/
|
|
11
13
|
declare const UserNotificationItem: {
|
|
12
|
-
({ notification }: UserNotificationItemProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
({ notification, menu, }: UserNotificationItemProps): import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
displayName: string;
|
|
14
16
|
};
|
|
15
17
|
export default UserNotificationItem;
|
|
@@ -5,7 +5,8 @@ import NotificationItemResource from "./NotificationItemResource.js";
|
|
|
5
5
|
import useDirectory from "../../../../../hooks/useDirectory/useDirectory.js";
|
|
6
6
|
import Avatar from "../../../../../components/Avatar/Avatar.js";
|
|
7
7
|
const UserNotificationItem = ({
|
|
8
|
-
notification
|
|
8
|
+
notification,
|
|
9
|
+
menu
|
|
9
10
|
}) => {
|
|
10
11
|
const {
|
|
11
12
|
getAvatarURL,
|
|
@@ -18,7 +19,7 @@ const UserNotificationItem = ({
|
|
|
18
19
|
} = notification, {
|
|
19
20
|
t
|
|
20
21
|
} = useTranslation(), userName = t(params.username);
|
|
21
|
-
return /* @__PURE__ */ jsx(CommonNotificationItem, { uri, message, date, picture: /* @__PURE__ */ jsx("a", { href: getUserbookURL(params.userId, "user"), title: userName, "data-testid": "notification-item-avatar", children: /* @__PURE__ */ jsx(Avatar, { "aria-label": t("homepage.notifications.avatar.placeholder"), src: getAvatarURL(params.userId, "user"), alt: userName, variant: "circle", className: "notification-item-avatar" }) }), children: /* @__PURE__ */ jsx(NotificationItemResource, { appCode: params.appCode }) });
|
|
22
|
+
return /* @__PURE__ */ jsx(CommonNotificationItem, { uri, message, date, menu, picture: /* @__PURE__ */ jsx("a", { href: getUserbookURL(params.userId, "user"), title: userName, "data-testid": "notification-item-avatar", children: /* @__PURE__ */ jsx(Avatar, { "aria-label": t("homepage.notifications.avatar.placeholder"), src: getAvatarURL(params.userId, "user"), alt: userName, variant: "circle", className: "notification-item-avatar" }) }), children: /* @__PURE__ */ jsx(NotificationItemResource, { appCode: params.appCode, appI18nKey: params.appI18nKey }) });
|
|
22
23
|
};
|
|
23
24
|
export {
|
|
24
25
|
UserNotificationItem as default
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { NotificationModel } from '@edifice.io/client';
|
|
2
|
-
type
|
|
2
|
+
type NotificationType = 'system' | 'user';
|
|
3
|
+
interface WebNotificationParamsBase {
|
|
4
|
+
appCode: string;
|
|
5
|
+
appI18nKey: string;
|
|
6
|
+
}
|
|
7
|
+
interface WebNotificationBase {
|
|
8
|
+
type: NotificationType;
|
|
3
9
|
id: string;
|
|
4
10
|
uri?: string;
|
|
5
11
|
message: string;
|
|
6
12
|
date: Date;
|
|
7
|
-
|
|
13
|
+
params: WebNotificationParamsBase;
|
|
14
|
+
}
|
|
8
15
|
/** Notification triggered by another user (e.g. shared a resource). */
|
|
9
16
|
export type UserWebNotification = WebNotificationBase & {
|
|
10
17
|
type: 'user';
|
|
11
|
-
params: {
|
|
12
|
-
appCode: string;
|
|
18
|
+
params: WebNotificationParamsBase & {
|
|
13
19
|
username: string;
|
|
14
20
|
userId: string;
|
|
15
21
|
};
|
|
@@ -17,11 +23,20 @@ export type UserWebNotification = WebNotificationBase & {
|
|
|
17
23
|
/** Notification triggered by an application event (no sender). */
|
|
18
24
|
export type SystemWebNotification = WebNotificationBase & {
|
|
19
25
|
type: 'system';
|
|
20
|
-
params: {
|
|
21
|
-
appCode: string;
|
|
22
|
-
};
|
|
23
26
|
};
|
|
24
27
|
/** Discriminated union — narrow on `type` to get the specific variant. */
|
|
25
28
|
export type WebNotification = UserWebNotification | SystemWebNotification;
|
|
29
|
+
export declare const getAppCodeAndI18nKey: (appCode: string) => [string, string];
|
|
30
|
+
/**
|
|
31
|
+
* Transforms a raw `NotificationModel` (API shape) into a `WebNotification`
|
|
32
|
+
* ready for rendering.
|
|
33
|
+
*
|
|
34
|
+
* Responsibilities:
|
|
35
|
+
* - Determines the variant: **user** when a `sender` is present, **system** otherwise.
|
|
36
|
+
* - Resolves the target URI from the model's `params` (handles both user and system naming conventions).
|
|
37
|
+
* - Converts the MongoDB `$date` timestamp to a JS `Date`.
|
|
38
|
+
* - Normalises the `type` field into a kebab-case `appCode` (e.g. `"BLOG_POST"` → `"blog-post"`).
|
|
39
|
+
* - Strips anchor tags from the message, keeping only the inner text as `<strong>`.
|
|
40
|
+
*/
|
|
26
41
|
export declare const notificationAdapter: (notification: NotificationModel) => WebNotification;
|
|
27
42
|
export {};
|
|
@@ -1,30 +1,45 @@
|
|
|
1
|
-
const resolveNotificationResourceUri = (params, type) => {
|
|
1
|
+
const resolveNotificationResourceUri = (params, type, appCode, eventType) => {
|
|
2
|
+
if (appCode === "timeline" && eventType === "NOTIFY-REPORT")
|
|
3
|
+
return "/admin";
|
|
2
4
|
if (type === "user")
|
|
3
5
|
return params.resourceUri || params.uri;
|
|
4
6
|
for (const [key, value] of Object.entries(params))
|
|
5
7
|
if (typeof value == "string" && value.length > 0 && key.endsWith("Uri") && key !== "profilUri" && key !== "resourceFolderUri")
|
|
6
8
|
return value;
|
|
7
|
-
}, parseNotificationMessage = (message) => message.replace(/<\/a>/gi, "</strong>").replace(/<a\b[^>]*>/gi, "<strong>"),
|
|
8
|
-
|
|
9
|
+
}, parseNotificationMessage = (message) => message.replace(/<\/a>/gi, "</strong>").replace(/<a\b[^>]*>/gi, "<strong>"), getAppCodeAndI18nKey = (appCode) => {
|
|
10
|
+
appCode = appCode.toLowerCase();
|
|
11
|
+
let appI18nKey = appCode;
|
|
12
|
+
switch (appCode) {
|
|
9
13
|
case "collaborativewall":
|
|
10
|
-
|
|
14
|
+
appCode = "collaborative-wall";
|
|
15
|
+
break;
|
|
11
16
|
case "formulaire":
|
|
12
|
-
|
|
17
|
+
appI18nKey = "formulaire", appCode = "forms";
|
|
18
|
+
break;
|
|
13
19
|
case "messagerie":
|
|
14
|
-
|
|
20
|
+
appI18nKey = appCode = "conversation";
|
|
21
|
+
break;
|
|
15
22
|
case "news":
|
|
16
|
-
|
|
23
|
+
appI18nKey = appCode = "actualites";
|
|
24
|
+
break;
|
|
17
25
|
case "homeworks":
|
|
18
|
-
|
|
26
|
+
appCode = "cahier-de-texte";
|
|
27
|
+
break;
|
|
19
28
|
case "userbook_motto":
|
|
29
|
+
appI18nKey = "userbook_motto", appCode = "userbook";
|
|
30
|
+
break;
|
|
20
31
|
case "userbook_mood":
|
|
32
|
+
appI18nKey = "userbook_mood", appCode = "userbook";
|
|
33
|
+
break;
|
|
21
34
|
case "userbook_discovervisiblegroups":
|
|
22
|
-
|
|
35
|
+
appI18nKey = "userbook_discovervisiblegroups", appCode = "userbook";
|
|
36
|
+
break;
|
|
23
37
|
default:
|
|
24
|
-
|
|
38
|
+
appI18nKey = appCode = appCode.replace(/_/g, "-");
|
|
25
39
|
}
|
|
40
|
+
return [appCode, appI18nKey];
|
|
26
41
|
}, notificationAdapter = (notification) => {
|
|
27
|
-
const type = notification.sender ? "user" : "system", uri = resolveNotificationResourceUri(notification.params, type), date = new Date(notification.date.$date),
|
|
42
|
+
const type = notification.sender ? "user" : "system", [appCode, appI18nKey] = getAppCodeAndI18nKey(notification.type), uri = resolveNotificationResourceUri(notification.params, type, appCode, notification["event-type"] || notification.eventType), date = new Date(notification.date.$date), message = parseNotificationMessage(notification.message), base = {
|
|
28
43
|
id: notification._id,
|
|
29
44
|
uri,
|
|
30
45
|
message,
|
|
@@ -38,16 +53,19 @@ const resolveNotificationResourceUri = (params, type) => {
|
|
|
38
53
|
// cannot be undefined if sender is present (user type)
|
|
39
54
|
userId: notification.sender,
|
|
40
55
|
// cannot be undefined if sender is present (user type)
|
|
41
|
-
appCode
|
|
56
|
+
appCode,
|
|
57
|
+
appI18nKey
|
|
42
58
|
}
|
|
43
59
|
} : {
|
|
44
60
|
...base,
|
|
45
61
|
type: "system",
|
|
46
62
|
params: {
|
|
47
|
-
appCode
|
|
63
|
+
appCode,
|
|
64
|
+
appI18nKey
|
|
48
65
|
}
|
|
49
66
|
};
|
|
50
67
|
};
|
|
51
68
|
export {
|
|
69
|
+
getAppCodeAndI18nKey,
|
|
52
70
|
notificationAdapter
|
|
53
71
|
};
|
|
@@ -2,8 +2,12 @@ import { NotificationModel } from '@edifice.io/client';
|
|
|
2
2
|
export interface UseNotificationListContainerReturn {
|
|
3
3
|
/** Array of notifications */
|
|
4
4
|
notifications: NotificationModel[] | undefined;
|
|
5
|
-
/** Array of notification types */
|
|
5
|
+
/** Array of all notification types available */
|
|
6
6
|
notificationTypes: string[] | undefined;
|
|
7
|
+
/** Array of notification types currently selected as filter */
|
|
8
|
+
selectedTypes: string[] | undefined;
|
|
9
|
+
/** Callback to change the selected notification types filter */
|
|
10
|
+
setSelectedTypes: (types: string[]) => void;
|
|
7
11
|
/** Indicates if there are more notifications to load */
|
|
8
12
|
hasNextPage: boolean | undefined;
|
|
9
13
|
/** Callback to load the next page of notifications */
|
|
@@ -18,3 +22,9 @@ export interface UseNotificationListContainerReturn {
|
|
|
18
22
|
* @returns Object containing notifications, loading state, and error state
|
|
19
23
|
*/
|
|
20
24
|
export declare const useNotificationListContainer: () => UseNotificationListContainerReturn;
|
|
25
|
+
/**
|
|
26
|
+
* Indicates whether the user has at least one notification dated today,
|
|
27
|
+
* across all notification types. Used to display a "new notification"
|
|
28
|
+
* badge on the notification bell icon, independently of the list overlay.
|
|
29
|
+
*/
|
|
30
|
+
export declare const useHasNotificationToday: () => boolean;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import { useNotificationTypes, useNotifications, useTimelinePreference, useSaveTimelinePreference } from "../services/queries/notification.js";
|
|
3
|
+
import useDate from "../../../../../hooks/useDate/useDate.js";
|
|
2
4
|
const useNotificationListContainer = () => {
|
|
3
5
|
const {
|
|
4
6
|
data: notificationTypes,
|
|
@@ -6,21 +8,51 @@ const useNotificationListContainer = () => {
|
|
|
6
8
|
isFetched: isFetchedTypes,
|
|
7
9
|
error: errorTypes
|
|
8
10
|
} = useNotificationTypes(), {
|
|
11
|
+
data: preference,
|
|
12
|
+
isFetched: isFetchedPreference
|
|
13
|
+
} = useTimelinePreference(), {
|
|
14
|
+
mutate: saveTimelinePreference
|
|
15
|
+
} = useSaveTimelinePreference(), [selectedTypes, setSelectedTypesState] = useState();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (selectedTypes === void 0 && isFetchedTypes && isFetchedPreference) {
|
|
18
|
+
const preferredTypes = preference == null ? void 0 : preference.type;
|
|
19
|
+
setSelectedTypesState(preferredTypes && preferredTypes.length > 0 ? preferredTypes : notificationTypes ?? []);
|
|
20
|
+
}
|
|
21
|
+
}, [selectedTypes, isFetchedTypes, isFetchedPreference, preference, notificationTypes]);
|
|
22
|
+
const setSelectedTypes = (types) => {
|
|
23
|
+
setSelectedTypesState(types), saveTimelinePreference({
|
|
24
|
+
...preference,
|
|
25
|
+
type: types
|
|
26
|
+
});
|
|
27
|
+
}, {
|
|
9
28
|
data: notifications,
|
|
10
29
|
hasNextPage,
|
|
11
30
|
isLoading: isLoadingNotifications,
|
|
12
31
|
error: errorNotifications,
|
|
13
32
|
fetchNextPage
|
|
14
|
-
} = useNotifications(
|
|
33
|
+
} = useNotifications(selectedTypes ?? [], isFetchedTypes && !!selectedTypes);
|
|
15
34
|
return {
|
|
16
35
|
notifications,
|
|
17
36
|
notificationTypes,
|
|
37
|
+
selectedTypes,
|
|
38
|
+
setSelectedTypes,
|
|
18
39
|
hasNextPage,
|
|
19
40
|
loadNextPage: () => fetchNextPage(),
|
|
20
41
|
isLoading: isLoadingTypes || isLoadingNotifications,
|
|
21
42
|
error: errorTypes || errorNotifications
|
|
22
43
|
};
|
|
44
|
+
}, useHasNotificationToday = () => {
|
|
45
|
+
const {
|
|
46
|
+
dateIsToday
|
|
47
|
+
} = useDate(), {
|
|
48
|
+
data: notificationTypes,
|
|
49
|
+
isFetched: isFetchedTypes
|
|
50
|
+
} = useNotificationTypes(), {
|
|
51
|
+
data: notifications
|
|
52
|
+
} = useNotifications(notificationTypes ?? [], isFetchedTypes);
|
|
53
|
+
return (notifications == null ? void 0 : notifications.some((notification) => dateIsToday(notification.date))) ?? !1;
|
|
23
54
|
};
|
|
24
55
|
export {
|
|
56
|
+
useHasNotificationToday,
|
|
25
57
|
useNotificationListContainer
|
|
26
58
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const notificationService: {
|
|
2
2
|
getNotifications(types: string[], page: number): Promise<import('@edifice.io/client').NotificationModel[]>;
|
|
3
3
|
getNotificationTypes(): Promise<string[]>;
|
|
4
|
+
reportNotification(id: string): Promise<any>;
|
|
5
|
+
deleteNotification(id: string): Promise<any>;
|
|
4
6
|
};
|
package/dist/modules/homepage/components/Notifications/services/api/notificationService.d.ts
CHANGED
|
@@ -12,4 +12,12 @@ export declare const createNotificationService: (baseURL: string) => {
|
|
|
12
12
|
*/
|
|
13
13
|
getNotifications(types: string[], page: number): Promise<NotificationModel[]>;
|
|
14
14
|
getNotificationTypes(): Promise<string[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Report a notification as inappropriate.
|
|
17
|
+
*/
|
|
18
|
+
reportNotification(id: string): Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Delete a notification.
|
|
21
|
+
*/
|
|
22
|
+
deleteNotification(id: string): Promise<any>;
|
|
15
23
|
};
|
|
@@ -14,6 +14,18 @@ const createNotificationService = (baseURL) => ({
|
|
|
14
14
|
},
|
|
15
15
|
getNotificationTypes() {
|
|
16
16
|
return odeServices.http().get(`${baseURL}/timeline/types`);
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* Report a notification as inappropriate.
|
|
20
|
+
*/
|
|
21
|
+
reportNotification(id) {
|
|
22
|
+
return odeServices.http().put(`${baseURL}/timeline/${id}/report`);
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* Delete a notification.
|
|
26
|
+
*/
|
|
27
|
+
deleteNotification(id) {
|
|
28
|
+
return odeServices.http().put(`${baseURL}/timeline/${id}`);
|
|
17
29
|
}
|
|
18
30
|
});
|
|
19
31
|
export {
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { NotificationModel } from '@edifice.io/client';
|
|
2
|
+
import { InfiniteData } from '@tanstack/react-query';
|
|
3
|
+
/** Shape of the `timeline` userbook preference (only `type` is read/written here). */
|
|
4
|
+
export interface TimelinePreference {
|
|
5
|
+
page?: number;
|
|
6
|
+
type: string[];
|
|
7
|
+
config?: Record<string, unknown>;
|
|
8
|
+
}
|
|
2
9
|
export declare const notificationQueryKeys: {
|
|
3
10
|
all: () => readonly ["notifications"];
|
|
4
11
|
notifications: (types?: string[]) => readonly ["notifications", "list", string[]];
|
|
5
12
|
types: () => readonly ["notifications", "types"];
|
|
13
|
+
preference: () => readonly ["notifications", "preference"];
|
|
6
14
|
};
|
|
7
15
|
export declare const notificationQueryOptions: {
|
|
8
16
|
getNotifications(types: string[], enabled: boolean): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseInfiniteQueryOptions<NotificationModel[], Error, NotificationModel[], NotificationModel[], readonly ["notifications", "list", string[]], number>, "queryFn"> & {
|
|
9
17
|
queryFn?: import('@tanstack/react-query').QueryFunction<NotificationModel[], readonly ["notifications", "list", string[]], number> | undefined;
|
|
10
18
|
} & {
|
|
11
|
-
queryKey: import('@tanstack/react-query').DataTag<readonly ["notifications", "list", string[]],
|
|
19
|
+
queryKey: import('@tanstack/react-query').DataTag<readonly ["notifications", "list", string[]], InfiniteData<NotificationModel[], unknown>>;
|
|
12
20
|
};
|
|
13
21
|
getNotificationTypes(): import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<string[], Error, string[], import('@tanstack/react-query').QueryKey>, "queryFn"> & {
|
|
14
22
|
queryFn?: import('@tanstack/react-query').QueryFunction<string[], import('@tanstack/react-query').QueryKey, never> | undefined;
|
|
@@ -18,3 +26,7 @@ export declare const notificationQueryOptions: {
|
|
|
18
26
|
};
|
|
19
27
|
export declare const useNotifications: (types?: string[], enabled?: boolean) => import('@tanstack/react-query').UseInfiniteQueryResult<NotificationModel[], Error>;
|
|
20
28
|
export declare const useNotificationTypes: () => import('@tanstack/react-query').UseQueryResult<string[], Error>;
|
|
29
|
+
export declare const useTimelinePreference: () => import('@tanstack/react-query').UseQueryResult<TimelinePreference, Error>;
|
|
30
|
+
export declare const useSaveTimelinePreference: () => import('@tanstack/react-query').UseMutationResult<void, Error, TimelinePreference, unknown>;
|
|
31
|
+
export declare const useReportNotification: () => import('@tanstack/react-query').UseMutationResult<any, Error, string, unknown>;
|
|
32
|
+
export declare const useDeleteNotification: () => import('@tanstack/react-query').UseMutationResult<any, Error, string, unknown>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { odeServices } from "@edifice.io/client";
|
|
2
|
+
import { useQuery, useInfiniteQuery, useMutation, useQueryClient, queryOptions, infiniteQueryOptions } from "@tanstack/react-query";
|
|
2
3
|
import { notificationService } from "../api/index.js";
|
|
3
4
|
const notificationQueryKeys = {
|
|
4
5
|
all: () => ["notifications"],
|
|
5
6
|
notifications: (types = []) => [...notificationQueryKeys.all(), "list", types],
|
|
6
|
-
types: () => [...notificationQueryKeys.all(), "types"]
|
|
7
|
+
types: () => [...notificationQueryKeys.all(), "types"],
|
|
8
|
+
preference: () => [...notificationQueryKeys.all(), "preference"]
|
|
7
9
|
}, notificationQueryOptions = {
|
|
8
10
|
getNotifications(types, enabled) {
|
|
9
11
|
return infiniteQueryOptions({
|
|
@@ -31,10 +33,45 @@ const notificationQueryKeys = {
|
|
|
31
33
|
queryFn: async () => notificationService.getNotificationTypes()
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
|
-
}, useNotifications = (types = [], enabled = !0) => useInfiniteQuery(notificationQueryOptions.getNotifications(types, enabled)), useNotificationTypes = () => useQuery(notificationQueryOptions.getNotificationTypes())
|
|
36
|
+
}, useNotifications = (types = [], enabled = !0) => useInfiniteQuery(notificationQueryOptions.getNotifications(types, enabled)), useNotificationTypes = () => useQuery(notificationQueryOptions.getNotificationTypes()), useTimelinePreference = () => useQuery({
|
|
37
|
+
queryKey: notificationQueryKeys.preference(),
|
|
38
|
+
queryFn: () => odeServices.conf().getPreference("timeline")
|
|
39
|
+
}), useSaveTimelinePreference = () => {
|
|
40
|
+
const queryClient = useQueryClient();
|
|
41
|
+
return useMutation({
|
|
42
|
+
mutationFn: (preference) => odeServices.conf().savePreference("timeline", preference),
|
|
43
|
+
onSuccess: (_data, preference) => {
|
|
44
|
+
queryClient.setQueryData(notificationQueryKeys.preference(), preference);
|
|
45
|
+
},
|
|
46
|
+
onError: () => {
|
|
47
|
+
queryClient.invalidateQueries({
|
|
48
|
+
queryKey: notificationQueryKeys.preference()
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}, useReportNotification = () => useMutation({
|
|
53
|
+
mutationFn: (id) => notificationService.reportNotification(id)
|
|
54
|
+
}), useDeleteNotification = () => {
|
|
55
|
+
const queryClient = useQueryClient();
|
|
56
|
+
return useMutation({
|
|
57
|
+
mutationFn: (id) => notificationService.deleteNotification(id),
|
|
58
|
+
onSuccess: (_data, id) => {
|
|
59
|
+
queryClient.setQueriesData({
|
|
60
|
+
queryKey: [...notificationQueryKeys.all(), "list"]
|
|
61
|
+
}, (data) => data && {
|
|
62
|
+
...data,
|
|
63
|
+
pages: data.pages.map((page) => page.filter((notification) => notification._id !== id))
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
35
68
|
export {
|
|
36
69
|
notificationQueryKeys,
|
|
37
70
|
notificationQueryOptions,
|
|
71
|
+
useDeleteNotification,
|
|
38
72
|
useNotificationTypes,
|
|
39
|
-
useNotifications
|
|
73
|
+
useNotifications,
|
|
74
|
+
useReportNotification,
|
|
75
|
+
useSaveTimelinePreference,
|
|
76
|
+
useTimelinePreference
|
|
40
77
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
3
|
import SvgIconRafterUp from "../../../icons/components/IconRafterUp.js";
|
|
4
|
+
import SvgIconUserSearch from "../../../icons/components/IconUserSearch.js";
|
|
4
5
|
import useToggle from "../../../../hooks/useToggle/useToggle.js";
|
|
5
6
|
import Flex from "../../../../components/Flex/Flex.js";
|
|
6
7
|
import Dropdown from "../../../../components/Dropdown/Dropdown.js";
|
|
7
8
|
import IconButton from "../../../../components/Button/IconButton.js";
|
|
9
|
+
import ButtonBeta from "../../../../components/ButtonBeta/ButtonBeta.js";
|
|
8
10
|
import { getRotateTransitionStyle } from "../../../../utilities/rotate-transition-style/get-rotate-transition-style.js";
|
|
9
11
|
const SchoolSpace = ({
|
|
10
12
|
schools,
|
|
@@ -13,16 +15,23 @@ const SchoolSpace = ({
|
|
|
13
15
|
}) => {
|
|
14
16
|
const [isExpanded, toggleExpanded] = useToggle(!1), {
|
|
15
17
|
t
|
|
16
|
-
} = useTranslation()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/* @__PURE__ */ jsx(
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
} = useTranslation();
|
|
19
|
+
if (!selectedSchool) return null;
|
|
20
|
+
const hasManySchools = schools && schools.length > 1, directoryUrl = `/userbook/annuaire#/search?${new URLSearchParams({
|
|
21
|
+
structure: selectedSchool.id
|
|
22
|
+
}).toString()}`;
|
|
23
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: "4", direction: "column", className: "school-space", children: [
|
|
24
|
+
/* @__PURE__ */ jsxs(Flex, { className: "school-space-container", justify: "center", gap: "4", align: "center", children: [
|
|
25
|
+
/* @__PURE__ */ jsx("b", { children: selectedSchool.name }),
|
|
26
|
+
hasManySchools && /* @__PURE__ */ jsx(Dropdown, { placement: "bottom-end", onToggle: toggleExpanded, children: (triggerProps) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27
|
+
/* @__PURE__ */ jsx(IconButton, { ...triggerProps, "aria-label": t("show"), color: "tertiary", variant: "ghost", icon: /* @__PURE__ */ jsx(SvgIconRafterUp, { className: "w-16 min-w-0", style: getRotateTransitionStyle(isExpanded, {
|
|
28
|
+
degrees: 180
|
|
29
|
+
}) }) }),
|
|
30
|
+
/* @__PURE__ */ jsx(Dropdown.Menu, { children: schools.map((school) => /* @__PURE__ */ jsx(Dropdown.Item, { onClick: () => onSelectedSchoolChange == null ? void 0 : onSelectedSchoolChange(school), children: /* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx("p", { children: school.name }) }) }, school.id)) })
|
|
31
|
+
] }) })
|
|
32
|
+
] }),
|
|
33
|
+
/* @__PURE__ */ jsx(ButtonBeta, { variant: "outline", className: "school-space-directory-button", leftIcon: /* @__PURE__ */ jsx(SvgIconUserSearch, {}), onClick: () => window.location.href = directoryUrl, children: t("homepage.school-space.directory") })
|
|
34
|
+
] });
|
|
26
35
|
};
|
|
27
36
|
export {
|
|
28
37
|
SchoolSpace as default
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
|
+
import SvgIconClass from "../../../icons/components/IconClass.js";
|
|
4
|
+
import { useProfileLinks } from "./hooks/useProfileLinks.js";
|
|
3
5
|
import HomeCard from "../HomeCard/HomeCard.js";
|
|
4
6
|
import Flex from "../../../../components/Flex/Flex.js";
|
|
5
7
|
import Avatar from "../../../../components/Avatar/Avatar.js";
|
|
8
|
+
import ButtonBeta from "../../../../components/ButtonBeta/ButtonBeta.js";
|
|
6
9
|
function UserSpace({
|
|
7
10
|
name,
|
|
8
11
|
avatar,
|
|
@@ -11,8 +14,8 @@ function UserSpace({
|
|
|
11
14
|
}) {
|
|
12
15
|
const {
|
|
13
16
|
t
|
|
14
|
-
} = useTranslation();
|
|
15
|
-
return /* @__PURE__ */ jsxs(HomeCard, { variant: "user", children: [
|
|
17
|
+
} = useTranslation(), links = useProfileLinks(profile);
|
|
18
|
+
return /* @__PURE__ */ jsxs(HomeCard, { variant: "user", footer: !!links && /* @__PURE__ */ jsx(Flex, { children: links.map((link, index) => /* @__PURE__ */ jsx(ButtonBeta, { size: "sm", variant: "ghost", leftIcon: /* @__PURE__ */ jsx(SvgIconClass, {}), onClick: () => window.location.href = link.url, children: link.text }, `${link.url}-${index}`)) }), children: [
|
|
16
19
|
/* @__PURE__ */ jsxs(Flex, { className: "user-space", direction: "row", gap: "8", children: [
|
|
17
20
|
/* @__PURE__ */ jsx(Avatar, { className: "user-space--avatar", size: "auto", alt: name, src: avatar, variant: "circle" }),
|
|
18
21
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Child, StructureChildren } from '@edifice.io/client';
|
|
2
|
+
export declare const childrenQueryKeys: {
|
|
3
|
+
all: (userId: string) => readonly ["children", string];
|
|
4
|
+
};
|
|
5
|
+
export declare const childrenQueryOptions: (userId: string | undefined, enabled: boolean) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<StructureChildren[], Error, Child[], import('@tanstack/react-query').QueryKey>, "queryFn"> & {
|
|
6
|
+
queryFn?: import('@tanstack/react-query').QueryFunction<StructureChildren[], import('@tanstack/react-query').QueryKey, never> | undefined;
|
|
7
|
+
} & {
|
|
8
|
+
queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, StructureChildren[]>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Fetches the children of a "Relative" user across all their structures,
|
|
12
|
+
* merged into a single list.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useChildren(userId: string | undefined, enabled: boolean): import('@tanstack/react-query').UseQueryResult<Child[], Error>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { odeServices } from "@edifice.io/client";
|
|
2
|
+
import { useQuery, queryOptions } from "@tanstack/react-query";
|
|
3
|
+
const childrenQueryKeys = {
|
|
4
|
+
all: (userId) => ["children", userId]
|
|
5
|
+
};
|
|
6
|
+
function flattenChildrenByStructure(structures) {
|
|
7
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
8
|
+
return structures.flatMap((structure) => structure.children).filter((child) => seenIds.has(child.id) ? !1 : (seenIds.add(child.id), !0));
|
|
9
|
+
}
|
|
10
|
+
const childrenQueryOptions = (userId, enabled) => queryOptions({
|
|
11
|
+
queryKey: childrenQueryKeys.all(userId ?? ""),
|
|
12
|
+
queryFn: () => odeServices.directory().getChildren(userId),
|
|
13
|
+
enabled: enabled && !!userId,
|
|
14
|
+
select: flattenChildrenByStructure
|
|
15
|
+
});
|
|
16
|
+
function useChildren(userId, enabled) {
|
|
17
|
+
return useQuery(childrenQueryOptions(userId, enabled));
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
childrenQueryKeys,
|
|
21
|
+
childrenQueryOptions,
|
|
22
|
+
useChildren
|
|
23
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { UserProfile } from '@edifice.io/client';
|
|
2
|
+
type ProfileLink = {
|
|
3
|
+
url: string;
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
/** Generates user's links to show in the UserSpace home component. */
|
|
7
|
+
export declare function useProfileLinks(profile: UserProfile[number]): Array<ProfileLink> | undefined;
|
|
8
|
+
export {};
|