From 5f66df8ecb621302f2fa9807e150b24b7c06e471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojta=20B=C3=B6hm?= Date: Thu, 15 Jan 2026 13:43:22 +0100 Subject: [PATCH 01/10] feat: add report issue button (ui only) --- src/features/dashboard/sidebar/footer.tsx | 42 +++++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/features/dashboard/sidebar/footer.tsx b/src/features/dashboard/sidebar/footer.tsx index ba7007b39..6183c9e26 100644 --- a/src/features/dashboard/sidebar/footer.tsx +++ b/src/features/dashboard/sidebar/footer.tsx @@ -12,7 +12,7 @@ import { SidebarMenuButton, SidebarMenuItem, } from '@/ui/primitives/sidebar' -import { Book, Github, MessageSquarePlus } from 'lucide-react' +import { Book, Bug, Github, MessageSquarePlus } from 'lucide-react' import Link from 'next/link' import DashboardSurveyPopover from '../navbar/dashboard-survey-popover' import TeamBlockageAlert from './blocked-banner' @@ -60,12 +60,17 @@ export default function DashboardSidebarFooter() { - {INCLUDE_DASHBOARD_FEEDBACK_SURVEY && ( - + + {INCLUDE_DASHBOARD_FEEDBACK_SURVEY && ( @@ -79,14 +84,37 @@ export default function DashboardSidebarFooter() { SIDEBAR_TRANSITION_CLASSNAMES )} > - + Feedback } /> - - )} + )} + {INCLUDE_DASHBOARD_FEEDBACK_SURVEY && ( + /* separator */ +
+ )} + + + + Report Issue + + + ) } From bd6b388ee20366dfe5f95b4286692930cde8d312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojta=20B=C3=B6hm?= Date: Thu, 15 Jan 2026 13:44:03 +0100 Subject: [PATCH 02/10] feat: add provisional reportIssue server action --- src/server/support/support-actions.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/server/support/support-actions.ts diff --git a/src/server/support/support-actions.ts b/src/server/support/support-actions.ts new file mode 100644 index 000000000..b79c423ad --- /dev/null +++ b/src/server/support/support-actions.ts @@ -0,0 +1,26 @@ +'use server' + +import { authActionClient } from '@/lib/clients/action' +import { z } from 'zod' + +const ReportIssueSchema = z.object({ + sandboxId: z.string().min(1, 'Sandbox ID is required'), + description: z.string().min(1, 'Description is required'), +}) + +export const reportIssueAction = authActionClient + .schema(ReportIssueSchema) + .metadata({ actionName: 'reportIssue' }) + .action(async ({ parsedInput, ctx }) => { + const { sandboxId, description } = parsedInput + const email = ctx.user.email + + console.log('reportIssueAction', { sandboxId, description, email }) + + // TODO: Call Plain API + // - email + // - sandboxId + // - description + + return { success: true } + }) From a73206c6175b29ef66c6246422774fefbf464da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojta=20B=C3=B6hm?= Date: Thu, 15 Jan 2026 13:45:48 +0100 Subject: [PATCH 03/10] feat: change tooltip copy --- src/features/dashboard/sidebar/footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/dashboard/sidebar/footer.tsx b/src/features/dashboard/sidebar/footer.tsx index 6183c9e26..c25106d9a 100644 --- a/src/features/dashboard/sidebar/footer.tsx +++ b/src/features/dashboard/sidebar/footer.tsx @@ -77,7 +77,7 @@ export default function DashboardSidebarFooter() { Date: Thu, 15 Jan 2026 14:20:09 +0100 Subject: [PATCH 04/10] feat: add report issue popover --- .../dashboard/navbar/report-issue-popover.tsx | 107 ++++++++++++++++++ src/features/dashboard/sidebar/footer.tsx | 27 +++-- src/ui/primitives/textarea.tsx | 4 +- 3 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 src/features/dashboard/navbar/report-issue-popover.tsx diff --git a/src/features/dashboard/navbar/report-issue-popover.tsx b/src/features/dashboard/navbar/report-issue-popover.tsx new file mode 100644 index 000000000..a701d6c9c --- /dev/null +++ b/src/features/dashboard/navbar/report-issue-popover.tsx @@ -0,0 +1,107 @@ +'use client' + +import { reportIssueAction } from '@/server/support/support-actions' +import { Button } from '@/ui/primitives/button' +import { + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/ui/primitives/card' +import { Input } from '@/ui/primitives/input' +import { Popover, PopoverContent, PopoverTrigger } from '@/ui/primitives/popover' +import { Textarea } from '@/ui/primitives/textarea' +import { useState } from 'react' +import { toast } from 'sonner' + +interface ReportIssuePopoverProps { + trigger: React.ReactNode +} + +export default function ReportIssuePopover({ + trigger, +}: ReportIssuePopoverProps) { + const [isOpen, setIsOpen] = useState(false) + const [sandboxId, setSandboxId] = useState('') + const [description, setDescription] = useState('') + const [isSubmitting, setIsSubmitting] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + if (!sandboxId.trim() || !description.trim()) { + toast.error('Please fill in all fields') + return + } + + setIsSubmitting(true) + + try { + const result = await reportIssueAction({ + sandboxId: sandboxId.trim(), + description: description.trim(), + }) + + if (result?.data?.success) { + toast.success('Issue reported successfully. Our team will review it shortly.') + setIsOpen(false) + setSandboxId('') + setDescription('') + } else { + toast.error('Failed to report issue. Please try again.') + } + } catch (error) { + console.error('Error reporting issue:', error) + toast.error('Failed to report issue. Please try again.') + } finally { + setIsSubmitting(false) + } + } + + return ( + + {trigger} + + + + Report Issue + + Our team will get back to you shortly + + + +
+ setSandboxId(e.target.value)} + disabled={isSubmitting} + /> +