B2B-88: add starter kit structure and elements

This commit is contained in:
devmc-ee
2025-06-08 16:18:30 +03:00
parent 657a36a298
commit e7b25600cb
1280 changed files with 77893 additions and 5688 deletions

View File

@@ -0,0 +1,2 @@
export * from './use-fetch-notifications';
export * from './use-dismiss-notification';

View File

@@ -0,0 +1,21 @@
import { useCallback } from 'react';
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
export function useDismissNotification() {
const client = useSupabase();
return useCallback(
async (notification: number) => {
const { error } = await client
.from('notifications')
.update({ dismissed: true })
.eq('id', notification);
if (error) {
throw error;
}
},
[client],
);
}

View File

@@ -0,0 +1,73 @@
import { useEffect } from 'react';
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;
dismissed: boolean;
type: 'info' | 'warning' | 'error';
created_at: string;
link: string | null;
};
export function useFetchNotifications({
onNotifications,
accountIds,
realtime,
}: {
onNotifications: (notifications: Notification[]) => unknown;
accountIds: string[];
realtime: boolean;
}) {
const { data: initialNotifications } = useFetchInitialNotifications({
accountIds,
});
useNotificationsStream({
onNotifications,
accountIds,
enabled: realtime,
});
useEffect(() => {
if (initialNotifications) {
onNotifications(initialNotifications);
}
}, [initialNotifications, onNotifications]);
}
function useFetchInitialNotifications(props: { accountIds: string[] }) {
const client = useSupabase();
const now = new Date().toISOString();
return useQuery({
queryKey: ['notifications', ...props.accountIds],
queryFn: async () => {
const { data } = await client
.from('notifications')
.select(
`id,
body,
dismissed,
type,
created_at,
link
`,
)
.in('account_id', props.accountIds)
.eq('dismissed', false)
.gt('expires_at', now)
.order('created_at', { ascending: false })
.limit(10);
return data;
},
refetchOnMount: false,
refetchOnWindowFocus: false,
});
}

View File

@@ -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]);
}