From cf5f914afa43e4531a27acfbfc5480c62317746d Mon Sep 17 00:00:00 2001 From: Dylan Vidal Date: Sun, 18 Jan 2026 11:10:33 -0500 Subject: [PATCH 01/16] respect newlines and modify max count limits --- .../_components/FileUploadResponsesTable.tsx | 4 +- .../_components/PerUserResponsesView.tsx | 10 +++- .../_components/ResponseBarChart.tsx | 2 +- .../ResponseHorizontalBarChart.tsx | 2 +- .../_components/ResponsePieChart.tsx | 2 +- .../responses/_components/ResponsesTable.tsx | 10 ++-- .../_components/question-response-card.tsx | 59 ++++++++++++++++--- packages/api/src/utils.ts | 14 +++-- packages/consts/src/knight-hacks.ts | 2 +- 9 files changed, 81 insertions(+), 24 deletions(-) diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/FileUploadResponsesTable.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/FileUploadResponsesTable.tsx index 8158a785f..cb10f7fd6 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/FileUploadResponsesTable.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/FileUploadResponsesTable.tsx @@ -46,7 +46,7 @@ export function FileUploadResponsesTable({ return ( - {question} + {question}

@@ -60,7 +60,7 @@ export function FileUploadResponsesTable({ return ( - {question} + {question}

{responses.length} {responses.length === 1 ? "response" : "responses"}

diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx index aa7b12fa1..44890b6e6 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx @@ -214,7 +214,7 @@ export function PerUserResponsesView({ return (
-

+

{question.question} {!question.optional && ( * @@ -234,7 +234,13 @@ export function PerUserResponsesView({ {formatResponseValue(answer)} ) : ( -

+

{formatResponseValue(answer)}

)} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseBarChart.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseBarChart.tsx index 88f277b9b..70764d2aa 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseBarChart.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseBarChart.tsx @@ -73,7 +73,7 @@ export function ResponseBarChart({ {/* question text as card title */} - {question} + {question} {/* show total number of responses */}

{responses.length} {responses.length === 1 ? "response" : "responses"} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseHorizontalBarChart.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseHorizontalBarChart.tsx index 4d939a3fe..872d2e1f8 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseHorizontalBarChart.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponseHorizontalBarChart.tsx @@ -88,7 +88,7 @@ export function ResponseHorizontalBarChart({ {/* question text as card title */} - {question} + {question} {/* show total number of responses */}

{responses.length} {responses.length === 1 ? "response" : "responses"} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsePieChart.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsePieChart.tsx index aecb61841..f3c45fedf 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsePieChart.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsePieChart.tsx @@ -77,7 +77,7 @@ export function ResponsePieChart({ {/* question text as card title */} - {question} + {question} {/* show total number of responses */}

{responses.length} {responses.length === 1 ? "response" : "responses"} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsesTable.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsesTable.tsx index 49d7342ec..9f90636c6 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsesTable.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/ResponsesTable.tsx @@ -35,7 +35,7 @@ export function ResponsesTable({ question, responses }: ResponsesTableProps) { return ( - {question} + {question}

@@ -49,7 +49,7 @@ export function ResponsesTable({ question, responses }: ResponsesTableProps) { return ( - {question} + {question} {/* show total response count */}

{responses.length} {responses.length === 1 ? "response" : "responses"} @@ -94,8 +94,10 @@ export function ResponsesTable({ question, responses }: ResponsesTableProps) { ); } catch { - // Not a valid URL, just display as string - displayValue = answer; + // Not a valid URL, just display as string (preserve newlines) + displayValue = ( + {answer} + ); } } else if (typeof answer === "object") { displayValue = JSON.stringify(answer); diff --git a/apps/blade/src/app/forms/[formName]/_components/question-response-card.tsx b/apps/blade/src/app/forms/[formName]/_components/question-response-card.tsx index fbe9fc9ad..cda67ace3 100644 --- a/apps/blade/src/app/forms/[formName]/_components/question-response-card.tsx +++ b/apps/blade/src/app/forms/[formName]/_components/question-response-card.tsx @@ -1,10 +1,10 @@ "use client"; -import type { z } from "zod"; +import { FileUp, Loader2, X } from "lucide-react"; +import Image from "next/image"; import * as React from "react"; import { useRef, useState } from "react"; -import Image from "next/image"; -import { FileUp, Loader2, X } from "lucide-react"; +import type { z } from "zod"; import type { QuestionValidator } from "@forge/consts/knight-hacks"; import { Button } from "@forge/ui/button"; @@ -22,6 +22,7 @@ import { SelectValue, } from "@forge/ui/select"; import { Slider } from "@forge/ui/slider"; +import { Textarea } from "@forge/ui/textarea"; import { TimePicker } from "@forge/ui/time-picker"; import { toast } from "@forge/ui/toast"; @@ -55,7 +56,7 @@ export function QuestionResponseCard({ {/* Header */}

-

+

{question.question} {isRequired && *}

@@ -106,19 +107,61 @@ function QuestionBody({ formId?: string; }) { switch (question.type) { - case "SHORT_ANSWER": - case "PARAGRAPH": + case "SHORT_ANSWER": { + const currentValue = (value as string) || ""; + const maxLength = 150; + const charCount = currentValue.length; + const isOverLimit = charCount > maxLength; + return ( -
+
onChange(e.target.value)} disabled={disabled} className="rounded-none border-x-0 border-b border-t-0 border-gray-300 bg-transparent px-0 shadow-none outline-none focus-visible:border-b-2 focus-visible:border-primary focus-visible:ring-0" /> +
+ + {charCount}/{maxLength} + +
); + } + case "PARAGRAPH": { + const currentValue = (value as string) || ""; + const maxLength = 750; + const charCount = currentValue.length; + const isOverLimit = charCount > maxLength; + + return ( +
+