Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "elo",
"version": "1.43.0",
"version": "1.43.1",
"private": true,
"type": "module",
"scripts": {
Expand Down
107 changes: 51 additions & 56 deletions src/app/(authenticated)/forms/[id]/responses/[responseId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { formatDistanceToNow, format } from "date-fns"
import { ptBR } from "date-fns/locale"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { StatusUpdateButton } from "@/components/forms/status-update-button"
import { ResponseDetails } from "@/components/forms/response-details"
import { EditResponseButton } from "@/components/forms/edit-response-button"
import { type Field } from "@/lib/form-types"
import { DashboardShell } from "@/components/ui/dashboard-shell"
import { FormsSubPageShell } from "@/components/forms/v2/forms-sub-page-shell"
import { FormsSubPageShell, FormsPanel } from "@/components/forms/v2/forms-sub-page-shell"
import { FormSectionCard } from "@/components/forms/v2/form-section-card"
import { FileText } from "lucide-react"
import { canAccessForm } from "@/lib/access-control"
import { formatFormResponseNumber } from "@/lib/utils/form-response-number"

Expand Down Expand Up @@ -112,51 +113,47 @@ export default async function ResponseDetailsPage({ params }: ResponseDetailsPag
}
description={`Formulário: ${response.form.title}`}
>
<div className="space-y-8">
<Card>
<CardHeader>
<div className="flex flex-col md:flex-row gap-y-4 justify-between items-center md:items-start">
<div className="flex flex-col md:flex-row items-center gap-3">
<Avatar>
<AvatarImage src={response.user.imageUrl ?? ""} alt={response.user.firstName ?? "Usuário"} />
<AvatarFallback>
{response.user.firstName?.charAt(0) ?? response.user.email.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<div>
<CardTitle className="overflow-hidden text-xl md:text-2xl text-center md:text-start overflow-ellipsis">
{response.user.firstName
? `${response.user.firstName} ${response.user.lastName ?? ""}`
: response.user.email}
</CardTitle>
<CardDescription className="overflow-hidden text-center md:text-start overflow-ellipsis">{response.user.email}</CardDescription>
</div>
</div>
<div className="flex flex-col items-end gap-2">
{getStatusBadge(response.status)}
{response.statusComment && (
<p className="text-sm text-muted-foreground max-w-[300px] text-right">{response.statusComment}</p>
)}
<div className="space-y-6">
<FormsPanel>
<div className="flex flex-col md:flex-row gap-y-4 justify-between items-center md:items-start">
<div className="flex flex-col md:flex-row items-center gap-3">
<Avatar>
<AvatarImage src={response.user.imageUrl ?? ""} alt={response.user.firstName ?? "Usuário"} />
<AvatarFallback>
{response.user.firstName?.charAt(0) ?? response.user.email.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<div className="min-w-0">
<h2 className="overflow-hidden text-xl md:text-2xl font-semibold leading-tight tracking-tight text-center md:text-start overflow-ellipsis">
{response.user.firstName
? `${response.user.firstName} ${response.user.lastName ?? ""}`
: response.user.email}
</h2>
<p className="overflow-hidden text-sm text-muted-foreground text-center md:text-start overflow-ellipsis">{response.user.email}</p>
</div>
</div>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<p className="text-muted-foreground">Data de envio:</p>
<p className="font-medium">
{format(new Date(response.createdAt), "dd/MM/yyyy 'às' HH:mm", { locale: ptBR })}
</p>
</div>
<div>
<p className="text-muted-foreground">Última atualização:</p>
<p className="font-medium">
{formatDistanceToNow(new Date(response.updatedAt), { addSuffix: true, locale: ptBR })}
</p>
</div>
<div className="flex flex-col items-end gap-2">
{getStatusBadge(response.status)}
{response.statusComment && (
<p className="text-sm text-muted-foreground max-w-[300px] text-right">{response.statusComment}</p>
)}
</div>
</div>
<div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-4 border-t border-[hsl(var(--v2-border-soft))] pt-4 text-sm">
<div>
<p className="text-muted-foreground">Data de envio:</p>
<p className="font-medium">
{format(new Date(response.createdAt), "dd/MM/yyyy 'às' HH:mm", { locale: ptBR })}
</p>
</div>
</CardContent>
</Card>
<div>
<p className="text-muted-foreground">Última atualização:</p>
<p className="font-medium">
{formatDistanceToNow(new Date(response.updatedAt), { addSuffix: true, locale: ptBR })}
</p>
</div>
</div>
</FormsPanel>

<div className="flex justify-end gap-2">
<EditResponseButton
Expand All @@ -174,18 +171,16 @@ export default async function ResponseDetailsPage({ params }: ResponseDetailsPag
)}
</div>

<Card>
<CardHeader>
<CardTitle>Respostas</CardTitle>
<CardDescription>Detalhes das respostas enviadas pelo usuário</CardDescription>
</CardHeader>
<CardContent>
<ResponseDetails
responseData={response.responses as Record<string, string | number | string[] | File[] | null | undefined>[]}
formFields={response.form.fields as unknown as Field[]}
/>
</CardContent>
</Card>
<FormSectionCard
icon={FileText}
title="Respostas"
description="Detalhes das respostas enviadas pelo usuário"
>
<ResponseDetails
responseData={response.responses as Record<string, string | number | string[] | File[] | null | undefined>[]}
formFields={response.form.fields as unknown as Field[]}
/>
</FormSectionCard>
</div>
</FormsSubPageShell>
</DashboardShell>
Expand Down
28 changes: 17 additions & 11 deletions src/components/forms/form-response.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { z } from "zod"
import { api } from "@/trpc/react"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { CheckCircle2, Send } from "lucide-react"
import { CheckCircle2, Send, Lock } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
// Email de criação de solicitação agora é enviado no router (form-response.ts)
import ReactMarkdown from "react-markdown"
Expand Down Expand Up @@ -356,16 +356,22 @@ export function FormResponseComponent({
)}

{field.type === "dynamic" && (
<div className="p-3 bg-muted rounded-md border border-muted-foreground/30">
<p className="text-sm font-medium">
{watch(field.name) ? (
watch(field.name)
) : (
<span className="text-muted-foreground italic">
Coletando seu {field.dynamicType === "user_name" ? "nome" : "setor"}...
</span>
)}
</p>
<div className="rounded-[var(--v2-radius-card,0.75rem)] border border-[hsl(var(--v2-border-soft,var(--border)))] bg-muted/40 px-3 py-2.5">
<div className="flex items-center justify-between gap-2">
<p className="min-w-0 truncate text-sm font-medium">
{watch(field.name) ? (
watch(field.name)
) : (
<span className="text-muted-foreground italic">
Coletando seu {field.dynamicType === "user_name" ? "nome" : "setor"}...
</span>
)}
</p>
<span className="inline-flex shrink-0 items-center gap-1 text-xs text-muted-foreground">
<Lock className="h-3 w-3" />
Preenchido automaticamente
</span>
</div>
<input type="hidden" {...register(field.name)} />
</div>
)}
Expand Down
26 changes: 13 additions & 13 deletions src/components/forms/responses-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState } from "react"
import { api } from "@/trpc/react"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { FormsPanel } from "@/components/forms/v2/forms-sub-page-shell"
import { Button } from "@/components/ui/button"
import { ChevronLeft, ChevronRight, Eye, FileText, Loader2, MessageSquare } from "lucide-react"
import Link from "next/link"
Expand Down Expand Up @@ -196,8 +196,8 @@ export function ResponsesList({ formId }: { formId: string }) {
<ResponsesFilters filters={filters} onFiltersChange={onFiltersChange} />
<div className="grid grid-cols-1 gap-6">
{responses.map((response) => (
<Card key={response.id}>
<CardHeader className="pb-3">
<FormsPanel key={response.id} className="p-0">
<div className="p-6 pb-3">
<div className="flex justify-between items-start">
<div className="flex items-center gap-3">
<Avatar>
Expand All @@ -207,21 +207,21 @@ export function ResponsesList({ formId }: { formId: string }) {
</AvatarFallback>
</Avatar>
<div>
<CardTitle className="text-lg">
<h3 className="text-lg font-semibold leading-none tracking-tight">
{response.user.firstName
? `${response.user.firstName} ${response.user.lastName ?? ""}`
: response.user.email}
</CardTitle>
<CardDescription>
</h3>
<div className="mt-1.5 text-sm text-muted-foreground">
Enviado {formatDistanceToNow(new Date(response.createdAt), { addSuffix: true, locale: ptBR })} <br />
{/* Campos personalizados selecionados */}
{(form?.fields as unknown as Field[] | undefined)?.filter(f => f.showInList).map(field => (
<div key={field.id} className="mt-1">
{field.label}: <strong>{formatResponseValue(response.responses[0]?.[field.name])}</strong>
</div>
))}
</CardDescription>
<CardContent className="pt-2 px-0">
</div>
<div className="pt-2">
{!!(response.FormResponseChat || response.formResponseChat) ? (
(response.FormResponseChat?.length ?? 0) > 0 || (response.formResponseChat?.length ?? 0) > 0 ? (
<div className="mt-2 space-y-2">
Expand Down Expand Up @@ -264,7 +264,7 @@ export function ResponsesList({ formId }: { formId: string }) {
<p className="text-[10px] text-muted-foreground italic">Carregando mensagens...</p>
</div>
)}
</CardContent>
</div>
</div>
</div>
<div className="flex flex-col items-end gap-2">
Expand All @@ -274,8 +274,8 @@ export function ResponsesList({ formId }: { formId: string }) {
)}
</div>
</div>
</CardHeader>
< CardFooter className="flex flex-col md:flex-row gap-y-2 items-end justify-between pt-3 border-t" >
</div>
<div className="flex flex-col md:flex-row gap-y-2 items-end justify-between border-t border-[hsl(var(--v2-border-soft))] p-6 pt-3">
<Link href={`/forms/${formId}/responses/${response.id}`}>
<Button variant="outline" size="sm">
<Eye className="h-4 w-4 mr-1" />
Expand All @@ -289,8 +289,8 @@ export function ResponsesList({ formId }: { formId: string }) {
currentComment={response.statusComment ?? ""}
/>
)}
</CardFooter>
</Card>
</div>
</FormsPanel>
))
}
</div >
Expand Down
Loading