From da7f3e5718b1c702b57d190b6cc3bf7c2b92dc87 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Thu, 1 Jan 2026 14:08:08 +0100 Subject: [PATCH] chore: Remove comments --- CLAUDE.md | 8 +++- apps/api/src/controllers/Campaigns.ts | 1 - apps/api/src/controllers/Contacts.ts | 1 - apps/api/src/controllers/Uploads.ts | 1 - .../jobs/__tests__/email-processor.test.ts | 6 --- .../__tests__/requestLogger.test.ts | 8 +--- apps/api/src/services/AnalyticsService.ts | 2 - apps/api/src/services/S3Service.ts | 1 - apps/api/src/services/SegmentService.ts | 1 - .../src/services/WorkflowExecutionService.ts | 1 - apps/web/src/components/ActivityFeed.tsx | 3 +- apps/web/src/lib/hooks/useAnalytics.ts | 6 +-- apps/web/src/lib/hooks/useContacts.ts | 3 +- apps/web/src/pages/analytics/index.tsx | 18 +++----- apps/web/src/pages/contacts/index.tsx | 3 +- apps/web/src/pages/manage/[id].tsx | 3 +- apps/web/src/pages/segments/[id].tsx | 3 +- apps/web/src/pages/workflows/[id].tsx | 3 +- packages/types/src/prisma/helpers.ts | 46 ------------------- 19 files changed, 22 insertions(+), 96 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ce313fb..65b9299 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -156,4 +156,10 @@ Required for builds and deployment (see turbo.json and .env.example): allows the same Docker image to be used across different environments by simply changing environment variables at runtime - **Frontend Variables**: Next.js apps use `NEXT_PUBLIC_*` prefixed variables that are embedded at build time for - client-side access \ No newline at end of file + client-side access + +## Plugins +There are two plugins installed for you to use. + +- frontend-design: This plugin can help you to create polished user interfaces. Use it when working on design-related tasks. +- superpowers: This plugin can help you with advanced tasks such as refactorings, new features or architectural changes. Use it when you need extra assistance beyond basic coding. \ No newline at end of file diff --git a/apps/api/src/controllers/Campaigns.ts b/apps/api/src/controllers/Campaigns.ts index e9d836e..8628d25 100644 --- a/apps/api/src/controllers/Campaigns.ts +++ b/apps/api/src/controllers/Campaigns.ts @@ -23,7 +23,6 @@ export class Campaigns { const {name, description, subject, body, from, fromName, replyTo, audienceType, audienceCondition, segmentId} = CampaignSchemas.create.parse(req.body); - // Validate audience-specific fields if (audienceType === CampaignAudienceType.SEGMENT && !segmentId) { throw new HttpException(400, 'Segment ID is required for SEGMENT audience type'); } diff --git a/apps/api/src/controllers/Contacts.ts b/apps/api/src/controllers/Contacts.ts index ba89952..382b2d2 100644 --- a/apps/api/src/controllers/Contacts.ts +++ b/apps/api/src/controllers/Contacts.ts @@ -14,7 +14,6 @@ const upload = multer({ fileSize: 5 * 1024 * 1024, // 5MB max file size }, fileFilter: (_req, file, cb) => { - // Only accept CSV files if (file.mimetype === 'text/csv' || file.originalname.endsWith('.csv')) { cb(null, true); } else { diff --git a/apps/api/src/controllers/Uploads.ts b/apps/api/src/controllers/Uploads.ts index 650123a..d0ff856 100644 --- a/apps/api/src/controllers/Uploads.ts +++ b/apps/api/src/controllers/Uploads.ts @@ -13,7 +13,6 @@ const upload = multer({ fileSize: 10 * 1024 * 1024, // 10MB max file size }, fileFilter: (_req, file, cb) => { - // Only accept image files const allowedMimeTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']; if (allowedMimeTypes.includes(file.mimetype)) { diff --git a/apps/api/src/jobs/__tests__/email-processor.test.ts b/apps/api/src/jobs/__tests__/email-processor.test.ts index 5342e36..881b762 100644 --- a/apps/api/src/jobs/__tests__/email-processor.test.ts +++ b/apps/api/src/jobs/__tests__/email-processor.test.ts @@ -29,12 +29,6 @@ describe('Email Processor', () => { status: EmailStatus.PENDING, }); - // Mock the email processor logic - // In a real implementation, you would: - // 1. Create job tester - // 2. Mock SES service - // 3. Process the job - // 4. Verify status changes // Simulate processing await prisma.email.update({ diff --git a/apps/api/src/middleware/__tests__/requestLogger.test.ts b/apps/api/src/middleware/__tests__/requestLogger.test.ts index bd48f36..816ad63 100644 --- a/apps/api/src/middleware/__tests__/requestLogger.test.ts +++ b/apps/api/src/middleware/__tests__/requestLogger.test.ts @@ -16,7 +16,6 @@ describe('Request Logger Middleware', () => { projectId = project.id; userId = user.id; - // Mock request object req = { method: 'POST', path: '/v1/send', @@ -334,12 +333,7 @@ describe('Request Logger Middleware', () => { await res.json!({success: true}); await new Promise(resolve => setTimeout(resolve, 100)); - // TODO: Add assertion to verify request was NOT logged when disabled - // const loggedRequest = await prisma.apiRequest.findUnique({ - // where: {id: 'test-request-id-123'}, - // }); - // expect(loggedRequest).toBeNull(); - + // Restore original value if (originalEnv !== undefined) { process.env.REQUEST_LOGGING = originalEnv; diff --git a/apps/api/src/services/AnalyticsService.ts b/apps/api/src/services/AnalyticsService.ts index 06aefeb..be96fef 100644 --- a/apps/api/src/services/AnalyticsService.ts +++ b/apps/api/src/services/AnalyticsService.ts @@ -68,8 +68,6 @@ export class AnalyticsService { return JSON.parse(cached); } - // Raw SQL query for efficient daily aggregation - // Using raw SQL because Prisma's groupBy is less efficient for date truncation const result = await prisma.$queryRaw< { date: Date; diff --git a/apps/api/src/services/S3Service.ts b/apps/api/src/services/S3Service.ts index 0962747..a36d89b 100644 --- a/apps/api/src/services/S3Service.ts +++ b/apps/api/src/services/S3Service.ts @@ -46,7 +46,6 @@ export async function initializeBucket(): Promise { let bucketExists = true; try { - // Check if bucket exists await s3Client.send( new HeadBucketCommand({ Bucket: S3_BUCKET, diff --git a/apps/api/src/services/SegmentService.ts b/apps/api/src/services/SegmentService.ts index 317e330..d246a68 100644 --- a/apps/api/src/services/SegmentService.ts +++ b/apps/api/src/services/SegmentService.ts @@ -9,7 +9,6 @@ import {HttpException} from '../exceptions/index.js'; import {EventService} from './EventService.js'; import {NtfyService} from './NtfyService.js'; -// Re-export types for use in other services export type {FilterCondition, FilterGroup, SegmentFilter} from '@plunk/types'; /** diff --git a/apps/api/src/services/WorkflowExecutionService.ts b/apps/api/src/services/WorkflowExecutionService.ts index d2eda32..0d85483 100644 --- a/apps/api/src/services/WorkflowExecutionService.ts +++ b/apps/api/src/services/WorkflowExecutionService.ts @@ -20,7 +20,6 @@ import {EmailService} from './EmailService.js'; import {NtfyService} from './NtfyService.js'; import {QueueService} from './QueueService.js'; -// Type aliases for workflow execution context type StepConfig = Prisma.JsonValue; type StepResult = Record; type WorkflowExecutionWithRelations = WorkflowExecution & {contact: Contact; workflow: Workflow}; diff --git a/apps/web/src/components/ActivityFeed.tsx b/apps/web/src/components/ActivityFeed.tsx index b909ba8..6752f5e 100644 --- a/apps/web/src/components/ActivityFeed.tsx +++ b/apps/web/src/components/ActivityFeed.tsx @@ -27,8 +27,7 @@ export function ActivityFeed({typeFilter, dateRangeDays = 30, contactId}: Activi return date.toISOString(); }, [dateRangeDays]); - // Fetch activities - const fetchActivities = useCallback( + const fetchActivities = useCallback( async (cursor?: string) => { try { if (cursor) { diff --git a/apps/web/src/lib/hooks/useAnalytics.ts b/apps/web/src/lib/hooks/useAnalytics.ts index dc89665..4899885 100644 --- a/apps/web/src/lib/hooks/useAnalytics.ts +++ b/apps/web/src/lib/hooks/useAnalytics.ts @@ -50,8 +50,7 @@ export function useAnalytics(options: UseAnalyticsOptions = {}): AnalyticsData { }, [days, options.startDate, options.endDate]); /* eslint-enable react-hooks/purity */ - // Fetch activity stats - const { + const { data: stats, error: statsError, isLoading: statsLoading, @@ -61,8 +60,7 @@ export function useAnalytics(options: UseAnalyticsOptions = {}): AnalyticsData { dedupingInterval: 10000, // Prevent duplicate requests within 10 seconds }); - // Fetch time series data (if endpoint exists) - const { + const { data: timeSeries, error: timeSeriesError, isLoading: timeSeriesLoading, diff --git a/apps/web/src/lib/hooks/useContacts.ts b/apps/web/src/lib/hooks/useContacts.ts index f206b52..d38507f 100644 --- a/apps/web/src/lib/hooks/useContacts.ts +++ b/apps/web/src/lib/hooks/useContacts.ts @@ -46,8 +46,7 @@ export function useContactFields() { }, ); - // Extract just the field names as strings - const fieldNames = (data?.fields || []).map(f => f.field); + const fieldNames = (data?.fields || []).map(f => f.field); return { fields: fieldNames, diff --git a/apps/web/src/pages/analytics/index.tsx b/apps/web/src/pages/analytics/index.tsx index d161b4c..d725be4 100644 --- a/apps/web/src/pages/analytics/index.tsx +++ b/apps/web/src/pages/analytics/index.tsx @@ -72,8 +72,7 @@ export default function AnalyticsPage() { return {startDate: start.toISOString(), endDate: end.toISOString()}; }, [days]); - // Fetch campaign stats from API - const {data: campaignStats} = useSWR<{ + const {data: campaignStats} = useSWR<{ total: number; active: number; completed: number; @@ -85,8 +84,7 @@ export default function AnalyticsPage() { dedupingInterval: 10000, }); - // Fetch top events from API - const {data: topEvents} = useSWR< + const {data: topEvents} = useSWR< { name: string; count: number; @@ -98,8 +96,7 @@ export default function AnalyticsPage() { dedupingInterval: 10000, }); - // Fetch top campaigns from API - const {data: topCampaigns} = useSWR< + const {data: topCampaigns} = useSWR< { id: string; subject: string; @@ -115,8 +112,7 @@ export default function AnalyticsPage() { dedupingInterval: 10000, }); - // Process time series data for charts - const chartData = useMemo(() => { + const chartData = useMemo(() => { if (timeSeries && timeSeries.length > 0) { return timeSeries.map(point => ({ date: new Date(point.date).toLocaleDateString('en-US', {month: 'short', day: 'numeric'}), @@ -131,13 +127,11 @@ export default function AnalyticsPage() { return []; }, [timeSeries]); - // Check if we have any real data - const hasData = useMemo(() => { + const hasData = useMemo(() => { return chartData.some(point => point.emails > 0 || point.opens > 0 || point.clicks > 0); }, [chartData]); - // Calculate cumulative totals - const cumulativeTotals = useMemo(() => { + const cumulativeTotals = useMemo(() => { return chartData.reduce( (acc, day) => ({ emails: acc.emails + (day.emails || 0), diff --git a/apps/web/src/pages/contacts/index.tsx b/apps/web/src/pages/contacts/index.tsx index 5126e70..0bde92e 100644 --- a/apps/web/src/pages/contacts/index.tsx +++ b/apps/web/src/pages/contacts/index.tsx @@ -67,8 +67,7 @@ export default function ContactsPage() { {revalidateOnFocus: false}, ); - // Update contacts when data changes - useEffect(() => { + useEffect(() => { if (data) { setContacts(data.data); if (!cursor) { diff --git a/apps/web/src/pages/manage/[id].tsx b/apps/web/src/pages/manage/[id].tsx index c21534c..b9fe525 100644 --- a/apps/web/src/pages/manage/[id].tsx +++ b/apps/web/src/pages/manage/[id].tsx @@ -33,8 +33,7 @@ export default function Manage() { const data = await network.fetch('GET', `/contacts/public/${id}`); setContact(data); - // Load translations for the project's language - const t = await createTranslator(data.language || 'en'); + const t = await createTranslator(data.language || 'en'); setTranslator(t); setError(null); diff --git a/apps/web/src/pages/segments/[id].tsx b/apps/web/src/pages/segments/[id].tsx index 8270a94..895001b 100644 --- a/apps/web/src/pages/segments/[id].tsx +++ b/apps/web/src/pages/segments/[id].tsx @@ -57,8 +57,7 @@ export default function SegmentDetailPage() { const [isComputing, setIsComputing] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); - // Initialize form when segment loads - useEffect(() => { + useEffect(() => { if (segment) { setName(segment.name); setDescription(segment.description || ''); diff --git a/apps/web/src/pages/workflows/[id].tsx b/apps/web/src/pages/workflows/[id].tsx index 0f05bc2..d073ef9 100644 --- a/apps/web/src/pages/workflows/[id].tsx +++ b/apps/web/src/pages/workflows/[id].tsx @@ -1556,8 +1556,7 @@ function EditStepDialog({step, workflowId, open, onOpenChange, onSuccess}: EditS const [name, setName] = useState(step.name); const [isSubmitting, setIsSubmitting] = useState(false); - // Get icon and colors for this step type - const Icon = STEP_TYPE_ICONS[step.type as keyof typeof STEP_TYPE_ICONS] || GitBranch; + const Icon = STEP_TYPE_ICONS[step.type as keyof typeof STEP_TYPE_ICONS] || GitBranch; const color = STEP_TYPE_COLORS[step.type as keyof typeof STEP_TYPE_COLORS] || '#6b7280'; const bgColor = STEP_TYPE_BG[step.type as keyof typeof STEP_TYPE_BG] || '#f3f4f6'; diff --git a/packages/types/src/prisma/helpers.ts b/packages/types/src/prisma/helpers.ts index 61cf4a6..182d301 100644 --- a/packages/types/src/prisma/helpers.ts +++ b/packages/types/src/prisma/helpers.ts @@ -7,58 +7,12 @@ import {Prisma} from '@plunk/db'; -/** - * Safely convert a value to Prisma.InputJsonValue for storing in JSON fields - * - * This helper provides better type safety than direct casting while acknowledging - * that Prisma cannot validate the JSON structure at compile time. - * - * @template T - The type being stored (for documentation purposes) - * @param value - The value to convert to Prisma JSON format - * @returns The value as Prisma.InputJsonValue - * - * @example - * ```typescript - * // Filter condition (complex nested object) - * const condition: FilterCondition = { logic: 'AND', groups: [...] }; - * await prisma.segment.create({ - * data: { - * condition: toPrismaJson(condition) - * } - * }); - * - * // Simple object - * const headers = { 'X-Custom': 'value' }; - * await prisma.email.create({ - * data: { - * headers: toPrismaJson(headers) - * } - * }); - * ``` - */ export function toPrismaJson(value: T | null | undefined): Prisma.InputJsonValue { // Prisma.InputJsonValue accepts: string | number | boolean | null | JsonObject | JsonArray // We trust that T is JSON-serializable at runtime (including null) return value as unknown as Prisma.InputJsonValue; } -/** - * Safely convert Prisma.JsonValue to a typed value when reading from JSON fields - * - * IMPORTANT: This does NOT perform runtime validation. It's a type-safe way to - * document what type you expect, but the caller must validate if needed. - * - * @template T - The expected type - * @param value - The JSON value from Prisma - * @returns The value as type T - * - * @example - * ```typescript - * const segment = await prisma.segment.findUnique({ where: { id } }); - * const condition = fromPrismaJson(segment.condition); - * // condition is now typed as FilterCondition (but not validated) - * ``` - */ export function fromPrismaJson(value: Prisma.JsonValue): T { return value as unknown as T; }