Notifications
Author: Carmine Antonio Bonavoglia Creation Date: 10/11/2025
Last Reviewer: Carmine Antonio Bonavoglia Last Updated: 10/11/2025
NotificationsSection Component
Purpose
Display and manage role-based notification preferences grouped by category.
Features
- Load preferences on mount — Fetch user's notification settings
- Group toggle — Switch all notifications in a group on/off
- API sync — Each toggle calls
updateNotificationPreferences()for each key - Role filtering — Only show groups the user has access to (via
preferences.hasOwnProperty(key)) - State restoration — On error, restore previous preferences
Notification Groups (8 Groups)
const NOTIFICATION_GROUPS = {
Admin: {
description: "Receive email notifications for administrative tasks...",
notificationKeys: [
"sendQuotationRequestEmailHttp",
"catalogOrderRejectionNotification",
"processSupportRequest",
],
},
Catalogue: {
description:
"Receive email notifications when new catalogues are published",
notificationKeys: ["newCatalogueHasBeenPublished"],
},
Orders: {
description: "Receive email notifications about quotations and orders",
notificationKeys: [
"sendQuotationRequestEmailHttpConfirmation",
"sendQuotationEmail",
"processCatalogOrderHttp",
],
},
Subscription: {
description:
"Receive email notifications about licence status and renewals",
notificationKeys: [
"licenseHasExpired",
"licenseHasBeenRenewed",
"subscriptionsMail",
],
},
Support: {
description:
"Receive email notifications when you submit support requests",
notificationKeys: ["processSupportRequestConfirmation"],
},
Teams: {
description:
"Receive email notifications about team invitations and member changes",
notificationKeys: [
"inviteMemberTeam",
"deletedMemberTeam",
"roleChangedMemberTeam",
],
},
"Weekly 3D Assets": {
description:
"Receive a weekly report on published variants and 3D assets",
notificationKeys: ["weeklyPublishedVariantsReport"],
},
"Weekly 3D Modelling": {
description:
"Receive a weekly report on assigned SKUs for 3D modelling",
notificationKeys: ["weeklySkuAssigned"],
},
};
Notification Groups Detail
Admin Group
- sendQuotationRequestEmailHttp — New quotation requests
- catalogOrderRejectionNotification — Order rejection notifications
- processSupportRequest — Support request processing
Catalogue Group
- newCatalogueHasBeenPublished — New catalogue publications
Orders Group
- sendQuotationRequestEmailHttpConfirmation — Quotation confirmations
- sendQuotationEmail — Quotation details
- processCatalogOrderHttp — Order processing
Subscription Group
- licenseHasExpired — License expiration alerts
- licenseHasBeenRenewed — License renewal notifications
- subscriptionsMail — Subscription status updates
Support Group
- processSupportRequestConfirmation — Support ticket confirmations
Teams Group
- inviteMemberTeam — Team invitation notifications
- deletedMemberTeam — Member removal notifications
- roleChangedMemberTeam — Role change notifications
Weekly 3D Assets Group
- weeklyPublishedVariantsReport — Weekly variant reports
Weekly 3D Modelling Group
- weeklySkuAssigned — Weekly SKU assignment reports
Layout
- Group name + description
- Toggle switch (currently disabled - for display only)
- Dividers between groups
- Empty state if no notifications accessible
Component State Management
const [preferences, setPreferences] = useState({}); // User's notification preferences
const [loading, setLoading] = useState(true); // Loading state
const [hasError, setHasError] = useState(false); // Error state
const [lastLoadedPreferences, setLastLoadedPreferences] = useState({}); // For rollback
Workflow: Load User Preferences
Step 1: Mount Component
useEffect(() => {
const loadPreferences = async () => {
try {
setLoading(true);
const userPrefs = await fetchNotificationPreferences(userId);
setPreferences(userPrefs);
setLastLoadedPreferences(userPrefs); // Store for rollback
} catch (error) {
console.error('Error loading preferences:', error);
setHasError(true);
} finally {
setLoading(false);
}
};
loadPreferences();
}, [userId]);
Workflow: Toggle Notification Group
Step 1: User Clicks Toggle
const handleGroupToggle = async (groupName, isEnabled) => {
const group = NOTIFICATION_GROUPS[groupName];
try {
// Update each notification key in the group
for (const key of group.notificationKeys) {
await updateNotificationPreferences(userId, key, isEnabled);
}
// Update local state
const updatedPrefs = { ...preferences };
group.notificationKeys.forEach(key => {
updatedPrefs[key] = isEnabled;
});
setPreferences(updatedPrefs);
message.success(`${groupName} notifications ${isEnabled ? 'enabled' : 'disabled'}`);
} catch (error) {
console.error('Error updating preferences:', error);
message.error('Failed to update notification preferences');
// Rollback to previous state
setPreferences(lastLoadedPreferences);
}
};
UI Display Logic
Determine Group Status:
const isGroupEnabled = (groupName) => {
const group = NOTIFICATION_GROUPS[groupName];
return group.notificationKeys.every(key => preferences[key] === true);
};
const isGroupPartiallyEnabled = (groupName) => {
const group = NOTIFICATION_GROUPS[groupName];
const enabledCount = group.notificationKeys.filter(
key => preferences[key] === true
).length;
return enabledCount > 0 && enabledCount < group.notificationKeys.length;
};
Render Group UI:
{NOTIFICATION_GROUPS.map((groupName, group) => (
<div key={groupName}>
<Row justify="space-between" align="middle">
<Col>
<Typography.Title level={5}>{groupName}</Typography.Title>
<Typography.Text type="secondary">
{group.description}
</Typography.Text>
</Col>
<Col>
<Switch
checked={isGroupEnabled(groupName)}
indeterminate={isGroupPartiallyEnabled(groupName)}
onChange={(checked) => handleGroupToggle(groupName, checked)}
/>
</Col>
</Row>
<Divider />
</div>
))}
Role-Based Filtering
Only show groups user has access to:
const visibleGroups = Object.keys(NOTIFICATION_GROUPS).filter(groupName => {
const group = NOTIFICATION_GROUPS[groupName];
// User sees group if they have at least one key in preferences
return group.notificationKeys.some(key => key in preferences);
});
Error Handling
| Error Type | User Feedback | Recovery |
|---|---|---|
| Load preferences fails | Show error message | Retry button to reload |
| Toggle fails | Error toast | Rollback to previous state |
| Network timeout | "Connection lost" message | Auto-retry with exponential backoff |
| Permission denied | "You don't have access" | None (disable all toggles) |
Edge Cases
Edge Case 1: Group Partially Enabled
Admin group has 3 notifications:
- Quotation requests: ✓ ENABLED
- Order rejection: ✗ DISABLED
- Support request: ✓ ENABLED
Result: Switch shows INDETERMINATE state (partial)
Action: User clicking toggle → ALL notifications in group toggle
Edge Case 2: No Preferences Found
User has no preference document
→ Show empty state
→ All toggles appear disabled
→ User can enable groups → Creates preference document
Edge Case 3: Preference Key Missing
Group has 3 keys but user only has 2 in preferences
→ Compare: preferences.hasOwnProperty(key)
→ Show only accessible notifications
→ Partial toggle behavior