diff --git a/src/client/index.ts b/src/client/index.ts index b5cd73cb7..84e2c906c 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -7,6 +7,7 @@ import { SERVER_EVENT_LISTENER, } from '../shared/network'; import PhoneService from './services/PhoneService'; +import { InsertNotification } from '../shared/Types'; const client = new Client({ debug: true, @@ -51,6 +52,10 @@ onNet(BROADCAST_EVENT_LISTENER, (data: { data: unknown; event: string }) => { global.SendNUIMessage({ type: NUI_BROADCAST_EVENT, payload: data }); }); +onNet('npwd:create-notification', (data: InsertNotification) => { + global.SendNUIMessage({ type: 'ADD_NOTIFICATION', payload: data }); +}); + RegisterCommand('npwd-toggle-phone', () => PhoneService.togglePhone(), false); RegisterKeyMapping('npwd-toggle-phone', 'Open Phone', 'keyboard', 'M'); diff --git a/src/server/exports/Notifications.ts b/src/server/exports/Notifications.ts new file mode 100644 index 000000000..ee14acfb4 --- /dev/null +++ b/src/server/exports/Notifications.ts @@ -0,0 +1,8 @@ +import { InsertNotification } from '../../shared/Types'; +import BroadcastService from '../services/BroadcastService'; + +const _exports = global.exports; + +_exports('createNotification', (src: number, notification: InsertNotification) => { + BroadcastService.createNotification(src, notification); +}); diff --git a/src/server/index.ts b/src/server/index.ts index 127a518d3..88e84d7e5 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -18,6 +18,7 @@ import { messagesRouter } from './router/messages'; import { conversationsRouter } from './router/conversations'; import { contactsRouter } from './router/contacts'; import { authRouter } from './router/auth'; +import './exports/Notifications'; function bootstrap() { initDB(); diff --git a/src/server/repositories/AuthRepository.ts b/src/server/repositories/AuthRepository.ts index 43a030759..0be6515e8 100644 --- a/src/server/repositories/AuthRepository.ts +++ b/src/server/repositories/AuthRepository.ts @@ -1,4 +1,3 @@ -import { set } from 'zod'; import { ResourceConfig, getServerConfig } from '../utils/config'; const _exports = global.exports; diff --git a/src/server/router/auth.ts b/src/server/router/auth.ts index 760015862..0823363ef 100644 --- a/src/server/router/auth.ts +++ b/src/server/router/auth.ts @@ -4,7 +4,7 @@ import DeviceService from '../services/DeviceService'; import PlayerService from '../services/PlayerService'; import SimCardService from '../services/SimCardService'; import { handleError } from '../utils/errors'; -import BroadcastService from '../services/BroadcastService'; +import { InsertNotification } from '../../shared/Types'; export const authRouter = new Router({ prefix: '/auth', @@ -82,9 +82,24 @@ authRouter.add('/source-by-device', async (ctx) => { } }); +// export const emitTo = (source: number, event: string, data: unknown) => { +// if (!isRunningInGame()) return; +// emitNet(event, source, data); +// }; + authRouter.add('/debug', async (ctx, next) => { try { const authorized = await PlayerService.authorizeDevice(ctx.source, 'debug'); + const authNotification: InsertNotification = { + title: 'Auth Notification', + description: `You are ${authorized ? 'authorized' : 'not authorized'} to debug`, + appId: 'settings', + path: '/home', + }; + + console.log('Emitting: npwd:add-notification', ctx.source, authNotification); + emitNet('npwd:add-notification', ctx.source, JSON.stringify(authNotification)); + console.log('Authorized', authorized); ctx.status = 200; diff --git a/src/server/services/BroadcastService.ts b/src/server/services/BroadcastService.ts index 64fe14404..d1f594645 100644 --- a/src/server/services/BroadcastService.ts +++ b/src/server/services/BroadcastService.ts @@ -1,6 +1,7 @@ import { RouterContext } from 'fivem-router'; import PlayerService from './PlayerService'; import { parseObjectToIsoString } from '../utils/date'; +import { InsertNotification } from '../../shared/Types'; interface EmitToNuiParams { ctx: RouterContext; @@ -16,6 +17,10 @@ interface EmitToNuisParams extends Omit { class BroadcastService { constructor() {} + private emitNet(event: string, source: number, data: string) { + emitNet(event, source, data); + } + private async getSourceFromSid(sid: number) { return await PlayerService.getSourceFromSid(sid); } @@ -41,6 +46,10 @@ class BroadcastService { ctx.emitToNui(src, event, parseObjectToIsoString(data)); } } + + public async createNotification(source: number, notification: InsertNotification) { + this.emitNet('npwd:create-notification', source, JSON.stringify(notification)); + } } export default new BroadcastService(); diff --git a/src/shared/Types.ts b/src/shared/Types.ts index 2f1d2a738..b134802e2 100644 --- a/src/shared/Types.ts +++ b/src/shared/Types.ts @@ -79,3 +79,24 @@ export interface Contact { sim_card_id: number; created_at: Date; } + +export interface Notification { + id: string; + path: string; + type: 'call' | 'generic'; + title: string; + timeout: number; + description: string; + created_at: string; + + appId?: string; + overline?: string; + dismissable?: boolean; +} + +export type InsertNotification = Omit & { + type?: Notification['type']; + timeout?: Notification['timeout']; + created_at?: Notification['created_at']; + dismissable?: Notification['dismissable']; +}; diff --git a/src/ui/src/contexts/NotificationContext/useNotifications.tsx b/src/ui/src/contexts/NotificationContext/useNotifications.tsx index fc72552b5..58c23360a 100644 --- a/src/ui/src/contexts/NotificationContext/useNotifications.tsx +++ b/src/ui/src/contexts/NotificationContext/useNotifications.tsx @@ -1,7 +1,8 @@ import { useContext } from 'react'; -import { Notification, NotificationsContext } from '.'; +import { NotificationsContext } from '.'; import { DEFAULT_NOTIFICATION_TIMEOUT } from '@/constants'; import { useLocation } from 'react-router'; +import { InsertNotification } from '../../../../shared/Types'; export const useNotifications = () => { const { pathname } = useLocation(); @@ -11,11 +12,7 @@ export const useNotifications = () => { throw new Error('useNotifications must be used within a NotificationsProvider'); } - const handleCreateNotification = ( - notification: Omit & { - timeout?: number; - }, - ) => { + const handleCreateNotification = (notification: InsertNotification) => { /** * If the notification is for the current path, don't show it. */ @@ -28,6 +25,7 @@ export const useNotifications = () => { { id: Math.random().toString(36).substring(7), ...notification, + type: notification.type || 'generic', timeout: notification.timeout || DEFAULT_NOTIFICATION_TIMEOUT, created_at: new Date().toISOString(), },