Update configuration settings and improve notifications
This commit updates the configuration settings and improves the notification functionality by filtering out duplicate notifications. It also includes changes to feature flag data types and removed dependencies in `package.json`, alongside updates to `pnpm-lock.yaml`.
This commit is contained in:
@@ -99,9 +99,9 @@ export function AccountSelector({
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className={cn(
|
||||
'dark:shadow-primary/10 group w-full min-w-0 max-w-full px-2',
|
||||
'dark:shadow-primary/10 group w-auto min-w-0 max-w-fit px-2',
|
||||
{
|
||||
'justify-between': !collapsed,
|
||||
'justify-start': !collapsed,
|
||||
'justify-center': collapsed,
|
||||
},
|
||||
)}
|
||||
@@ -124,14 +124,10 @@ export function AccountSelector({
|
||||
>
|
||||
{(account) => (
|
||||
<span className={'flex max-w-full items-center space-x-2'}>
|
||||
<Avatar
|
||||
className={
|
||||
'group-hover:border-border h-6 w-6 border border-transparent'
|
||||
}
|
||||
>
|
||||
<Avatar className={'h-5 w-5'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback>
|
||||
<AvatarFallback className={'group-hover:bg-background'}>
|
||||
{account.label ? account.label[0] : ''}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
@@ -147,7 +143,7 @@ export function AccountSelector({
|
||||
)}
|
||||
</If>
|
||||
|
||||
<CaretSortIcon className="ml-1 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
|
||||
@@ -188,7 +184,7 @@ export function AccountSelector({
|
||||
data-name={account.label}
|
||||
data-slug={account.value}
|
||||
className={cn(
|
||||
'group flex justify-between transition-colors',
|
||||
'group my-1 flex justify-between transition-colors',
|
||||
{
|
||||
['bg-muted']: value === account.value,
|
||||
},
|
||||
@@ -205,19 +201,16 @@ export function AccountSelector({
|
||||
}}
|
||||
>
|
||||
<div className={'flex items-center'}>
|
||||
<Avatar
|
||||
className={cn(
|
||||
'mr-2 h-6 w-6 border border-transparent',
|
||||
{
|
||||
['border-border']: value === account.value,
|
||||
['group-hover:border-border ']:
|
||||
value !== account.value,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Avatar className={'mr-2 h-5 w-5'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback>
|
||||
<AvatarFallback
|
||||
className={cn({
|
||||
['bg-background']: value === account.value,
|
||||
['group-hover:bg-background']:
|
||||
value !== account.value,
|
||||
})}
|
||||
>
|
||||
{account.label ? account.label[0] : ''}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
@@ -241,7 +234,7 @@ export function AccountSelector({
|
||||
<Button
|
||||
data-test={'create-team-account-trigger'}
|
||||
variant="ghost"
|
||||
className="w-full justify-start"
|
||||
className="w-full justify-start rounded-none"
|
||||
onClick={() => {
|
||||
setIsCreatingAccount(true);
|
||||
setOpen(false);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Bell, CircleAlert, Info, TriangleAlert, XIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -33,7 +33,15 @@ export function NotificationsPopover(params: {
|
||||
|
||||
const onNotifications = useCallback(
|
||||
(notifications: PartialNotification[]) => {
|
||||
setNotifications((existing) => [...notifications, ...existing]);
|
||||
setNotifications((existing) => {
|
||||
const unique = new Set(existing.map((notification) => notification.id));
|
||||
|
||||
const notificationsFiltered = notifications.filter(
|
||||
(notification) => !unique.has(notification.id),
|
||||
);
|
||||
|
||||
return [...notificationsFiltered, ...existing];
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
@@ -108,6 +116,12 @@ export function NotificationsPopover(params: {
|
||||
return text.slice(0, 1).toUpperCase() + text.slice(1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setNotifications([]);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Popover modal open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
|
||||
@@ -4,6 +4,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
|
||||
|
||||
import { useNotificationsStream } from './use-notifications-stream';
|
||||
|
||||
type Notification = {
|
||||
id: number;
|
||||
body: string;
|
||||
@@ -22,41 +24,21 @@ export function useFetchNotifications({
|
||||
accountIds: string[];
|
||||
realtime: boolean;
|
||||
}) {
|
||||
const { data: notifications } = useFetchInitialNotifications({ accountIds });
|
||||
const client = useSupabase();
|
||||
const { data: initialNotifications } = useFetchInitialNotifications({
|
||||
accountIds,
|
||||
});
|
||||
|
||||
useNotificationsStream({
|
||||
onNotifications,
|
||||
accountIds,
|
||||
enabled: realtime,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let realtimeSubscription: { unsubscribe: () => void } | null = null;
|
||||
|
||||
if (realtime) {
|
||||
const channel = client.channel('notifications-channel');
|
||||
|
||||
realtimeSubscription = channel
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{
|
||||
event: 'INSERT',
|
||||
schema: 'public',
|
||||
filter: `account_id=in.(${accountIds.join(', ')})`,
|
||||
table: 'notifications',
|
||||
},
|
||||
(payload) => {
|
||||
onNotifications([payload.new as Notification]);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
if (initialNotifications) {
|
||||
onNotifications(initialNotifications);
|
||||
}
|
||||
|
||||
if (notifications) {
|
||||
onNotifications(notifications);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (realtimeSubscription) {
|
||||
realtimeSubscription.unsubscribe();
|
||||
}
|
||||
};
|
||||
}, [client, onNotifications, accountIds, realtime, notifications]);
|
||||
}, [initialNotifications, onNotifications]);
|
||||
}
|
||||
|
||||
function useFetchInitialNotifications(props: { accountIds: string[] }) {
|
||||
@@ -86,5 +68,6 @@ function useFetchInitialNotifications(props: { accountIds: string[] }) {
|
||||
return data;
|
||||
},
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
|
||||
|
||||
type Notification = {
|
||||
id: number;
|
||||
body: string;
|
||||
dismissed: boolean;
|
||||
type: 'info' | 'warning' | 'error';
|
||||
created_at: string;
|
||||
link: string | null;
|
||||
};
|
||||
|
||||
export function useNotificationsStream(params: {
|
||||
onNotifications: (notifications: Notification[]) => void;
|
||||
accountIds: string[];
|
||||
enabled: boolean;
|
||||
}) {
|
||||
const client = useSupabase();
|
||||
|
||||
const { data: subscription } = useQuery({
|
||||
enabled: params.enabled,
|
||||
queryKey: ['realtime-notifications', ...params.accountIds],
|
||||
queryFn: () => {
|
||||
const channel = client.channel('notifications-channel');
|
||||
|
||||
return channel
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{
|
||||
event: 'INSERT',
|
||||
schema: 'public',
|
||||
filter: `account_id=in.(${params.accountIds.join(', ')})`,
|
||||
table: 'notifications',
|
||||
},
|
||||
(payload) => {
|
||||
params.onNotifications([payload.new as Notification]);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
void subscription?.unsubscribe();
|
||||
};
|
||||
}, [subscription]);
|
||||
}
|
||||
Reference in New Issue
Block a user