Files
myeasycms-v2/packages/features/event-management/src/server/services/event-communication.service.ts
T. Zehetbauer 9d5fe58ee3
Some checks failed
Workflow / ʦ TypeScript (push) Failing after 5m42s
Workflow / ⚫️ Test (push) Has been skipped
feat: add shared notification, communication, and export services for bookings, courses, and events; introduce btree_gist extension and new booking atomic function
2026-04-03 17:03:34 +02:00

100 lines
2.7 KiB
TypeScript

import 'server-only';
import type { SupabaseClient } from '@supabase/supabase-js';
import type { Database } from '@kit/supabase/database';
interface CommunicationListOptions {
type?: string;
direction?: string;
search?: string;
page?: number;
pageSize?: number;
}
interface CreateCommunicationInput {
accountId: string;
entityId: string;
type: string;
direction?: string;
subject?: string;
body?: string;
emailTo?: string;
emailCc?: string;
attachmentPaths?: string[];
}
export function createEventCommunicationService(
client: SupabaseClient<Database>,
) {
return new EventCommunicationService(client);
}
class EventCommunicationService {
constructor(private readonly client: SupabaseClient<Database>) {}
async list(
eventId: string,
accountId: string,
opts?: CommunicationListOptions,
) {
let query = (this.client.from as CallableFunction)('module_communications')
.select('*', { count: 'exact' })
.eq('module', 'events')
.eq('entity_id', eventId)
.eq('account_id', accountId)
.order('created_at', { ascending: false });
if (opts?.type) query = query.eq('type', opts.type);
if (opts?.direction) query = query.eq('direction', opts.direction);
if (opts?.search) {
const escaped = opts.search.replace(/[%_\\]/g, '\\$&');
query = query.or(`subject.ilike.%${escaped}%,body.ilike.%${escaped}%`);
}
const page = opts?.page ?? 1;
const pageSize = opts?.pageSize ?? 25;
query = query.range((page - 1) * pageSize, page * pageSize - 1);
const { data, error, count } = await query;
if (error) throw error;
return { data: data ?? [], total: count ?? 0, page, pageSize };
}
async create(input: CreateCommunicationInput, userId: string) {
const { data, error } = await (this.client.from as CallableFunction)(
'module_communications',
)
.insert({
account_id: input.accountId,
module: 'events',
entity_id: input.entityId,
type: input.type,
direction: input.direction ?? 'internal',
subject: input.subject ?? null,
body: input.body ?? null,
email_to: input.emailTo ?? null,
email_cc: input.emailCc ?? null,
attachment_paths: input.attachmentPaths ?? null,
created_by: userId,
})
.select(
'id, account_id, module, entity_id, type, direction, subject, email_to, created_at, created_by',
)
.single();
if (error) throw error;
return data;
}
async delete(communicationId: string) {
const { error } = await (this.client.from as CallableFunction)(
'module_communications',
)
.delete()
.eq('id', communicationId)
.eq('module', 'events');
if (error) throw error;
}
}