🆕 Redesign of HC Club buy, now also give as gift

This commit is contained in:
duckietm
2026-05-21 14:00:03 +02:00
parent 690a196d42
commit 49917ed49b
5 changed files with 234 additions and 97 deletions
+1 -42
View File
@@ -15,19 +15,6 @@ const getTimeZeroPadded = (time: number) =>
let modDisclaimerTimeout: ReturnType<typeof setTimeout> = null;
const recentBadgeNotifications = new Set<string>();
/**
* Internal singleton state + actions for the notification subsystem.
* Public consumers should reach for useNotificationState (read-only —
* the queue arrays for the renderer) or useNotificationActions (the
* imperative simpleAlert / showConfirm / showSingleBubble / etc.).
* useNotification is the legacy shim that composes both.
*
* Wrapped in useBetween at each public-hook layer so all consumers see
* the same instance, matching the previous useBetween(useNotificationState)
* behavior — required because ~30 useMessageEvent listeners live inside
* this hook and need to register exactly once across the tree.
*/
const useNotificationStore = () =>
{
const [ alerts, setAlerts ] = useState<NotificationAlertItem[]>([]);
@@ -242,7 +229,6 @@ const useNotificationStore = () =>
{
const parser = event.getParser();
// Skip if BadgeReceivedEvent already showed a notification for this badge
if(recentBadgeNotifications.has(parser.data.badgeCode)) return;
recentBadgeNotifications.add(parser.data.badgeCode);
@@ -258,7 +244,6 @@ const useNotificationStore = () =>
{
const parser = event.getParser();
// Skip if AchievementNotificationMessageEvent already showed a notification for this badge
if(recentBadgeNotifications.has(parser.badgeCode)) return;
recentBadgeNotifications.add(parser.badgeCode);
@@ -266,9 +251,6 @@ const useNotificationStore = () =>
const badgeName = LocalizeBadgeName(parser.badgeCode);
const badgeImage = GetSessionDataManager().getBadgeUrl(parser.badgeCode);
// senderName is non-empty only when a staff member awarded the badge
// via the `:badge` command. Empty for achievements, catalog buys,
// wired rewards, poll rewards, etc.
const senderName = parser.senderName || '';
showSingleBubble(badgeName, NotificationBubbleType.BADGE_RECEIVED, badgeImage, parser.badgeCode, senderName);
@@ -392,8 +374,7 @@ const useNotificationStore = () =>
{
const parser = event.getParser();
// Skip badge notifications — handled by BadgeReceivedEvent with "Wear" button
if(parser.type === 'badge_received' || parser.type === 'badges' || parser.type.includes('badge')) return;
if(parser.type === 'badge_received' || parser.type === 'badges') return;
showNotification(parser.type, parser.parameters);
});
@@ -512,14 +493,6 @@ const useNotificationStore = () =>
return { alerts, bubbleAlerts, confirms, simpleAlert, showNitroAlert, showTradeAlert, showConfirm, showSingleBubble, closeAlert, closeBubbleAlert, closeConfirm };
};
/**
* Read-only slice of the notification store: the three queue arrays
* (alerts, bubbleAlerts, confirms) that the renderer view layer drains.
*
* Consumers that only need to *show* a notification should use
* useNotificationActions instead — the queues are an implementation
* detail of the global NotificationView component.
*/
export const useNotificationState = () =>
{
const { alerts, bubbleAlerts, confirms } = useBetween(useNotificationStore);
@@ -527,14 +500,6 @@ export const useNotificationState = () =>
return { alerts, bubbleAlerts, confirms };
};
/**
* Imperative slice of the notification store: 8 entry points covering
* the alert / bubble / confirm / trade-alert flows plus the matching
* close handlers. ~40 consumers across the codebase only use one or
* two of these — splitting the slice off keeps their dependency
* surface honest and makes it greppable which call sites
* dismiss-vs-show.
*/
export const useNotificationActions = () =>
{
const {
@@ -560,10 +525,4 @@ export const useNotificationActions = () =>
};
};
/**
* @deprecated Prefer `useNotificationState` (queue arrays) and
* `useNotificationActions` (imperative show/close helpers) directly.
* This shim composes both into the historical `useNotification()`
* shape so the existing 40+ consumers keep working unchanged.
*/
export const useNotification = () => useBetween(useNotificationStore);