diff --git a/apps/web/src/actions/admin/weeklyEmail/enqueueWeeklyEmail.ts b/apps/web/src/actions/admin/weeklyEmail/enqueueWeeklyEmail.ts new file mode 100644 index 0000000000..2b402cdb13 --- /dev/null +++ b/apps/web/src/actions/admin/weeklyEmail/enqueueWeeklyEmail.ts @@ -0,0 +1,38 @@ +'use server' + +import { withAdmin } from '../../procedures' +import { z } from 'zod' +import { queues } from '@latitude-data/core/queues' + +export const enqueueWeeklyEmailAction = withAdmin + .inputSchema( + z.object({ + workspaceId: z.number(), + emails: z.string().optional(), + }), + ) + .action(async ({ parsedInput }) => { + const { workspaceId, emails } = parsedInput + + // Parse comma-separated emails if provided + const emailList = emails + ? emails + .split(',') + .map((e) => e.trim()) + .filter((e) => e.length > 0) + : undefined + + const { maintenanceQueue } = await queues() + await maintenanceQueue.add( + 'sendWeeklyEmailJob', + { + workspaceId, + emails: emailList, + }, + { + jobId: `weekly-email-manual-${workspaceId}-${Date.now()}`, + }, + ) + + return { success: true } + }) diff --git a/apps/web/src/app/(admin)/backoffice/_components/BackofficeTabs/index.tsx b/apps/web/src/app/(admin)/backoffice/_components/BackofficeTabs/index.tsx index c25d967f02..1156a25c35 100644 --- a/apps/web/src/app/(admin)/backoffice/_components/BackofficeTabs/index.tsx +++ b/apps/web/src/app/(admin)/backoffice/_components/BackofficeTabs/index.tsx @@ -61,6 +61,11 @@ export function BackofficeTabs({ children }: { children: ReactNode }) { value: BackofficeRoutes.integrations, route: ROUTES.backoffice.integrations.root, }, + { + label: 'Weekly', + value: BackofficeRoutes.weekly, + route: ROUTES.backoffice.weekly.root, + }, ]} selected={selected} /> diff --git a/apps/web/src/app/(admin)/backoffice/search/workspace/[id]/_components/WorkspaceDashboard/index.tsx b/apps/web/src/app/(admin)/backoffice/search/workspace/[id]/_components/WorkspaceDashboard/index.tsx index 28cac57d81..0d49f8a3ce 100644 --- a/apps/web/src/app/(admin)/backoffice/search/workspace/[id]/_components/WorkspaceDashboard/index.tsx +++ b/apps/web/src/app/(admin)/backoffice/search/workspace/[id]/_components/WorkspaceDashboard/index.tsx @@ -92,6 +92,15 @@ export function WorkspaceDashboard({ workspace }: Props) { issuesUnlocked={workspace.issuesUnlocked} />
+ + + { + const workspaceIdParam = searchParams.get('workspaceId') + if (workspaceIdParam) { + setWorkspaceId(workspaceIdParam) + } + }, [searchParams]) + + const { execute: enqueueEmail, isPending } = useLatitudeAction( + enqueueWeeklyEmailAction, + { + onSuccess: () => { + toast({ + title: 'Success', + description: 'Weekly email job has been enqueued successfully', + }) + // Clear form + setWorkspaceId('') + setEmails('') + }, + onError: (error) => { + toast({ + title: 'Error', + description: error.message, + variant: 'destructive', + }) + }, + }, + ) + + const handleSubmit = useCallback( + (e: FormEvent) => { + e.preventDefault() + + const parsedWorkspaceId = parseInt(workspaceId) + if (isNaN(parsedWorkspaceId)) { + toast({ + title: 'Invalid Workspace ID', + description: 'Please enter a valid numeric workspace ID', + variant: 'destructive', + }) + return + } + + enqueueEmail({ + workspaceId: parsedWorkspaceId, + emails: emails.trim() || undefined, + }) + }, + [workspaceId, emails, enqueueEmail, toast], + ) + + return ( +
+
+ Workspace ID + setWorkspaceId(e.target.value)} + required + /> + + The ID of the workspace to send the weekly email for + +
+ +
+ Email Addresses (Optional) +