mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-29 18:00:26 -06:00
analytics layout
This commit is contained in:
@@ -7,9 +7,7 @@ interface Props {
|
||||
KPI: string;
|
||||
typeText?: boolean;
|
||||
label: string;
|
||||
hasToolTip?: boolean;
|
||||
toolTipText: string;
|
||||
hasTrend?: boolean;
|
||||
trend: number;
|
||||
}
|
||||
|
||||
@@ -18,30 +16,27 @@ const AnalyticsCard: React.FC<Props> = ({
|
||||
KPI,
|
||||
typeText = false,
|
||||
label,
|
||||
hasToolTip = false,
|
||||
toolTipText,
|
||||
hasTrend = false,
|
||||
trend,
|
||||
}) => {
|
||||
return (
|
||||
<div className="relative px-4 pt-5 overflow-hidden bg-white rounded-lg shadow sm:pt-6 sm:px-6s">
|
||||
<div className="inline-flex items-center justify-center text-ui-gray-dark">
|
||||
<div className="grid content-between px-4 py-2 bg-white rounded-md shadow-md">
|
||||
<div className="inline-flex items-center text-sm text-ui-gray-dark">
|
||||
{label}{" "}
|
||||
{hasToolTip && (
|
||||
{toolTipText && (
|
||||
<QuestionMarkCircleIcon className="w-4 h-4 ml-1 text-red hover:text-ui-gray-dark" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
`justify-between font-bold leading-none `,
|
||||
typeText ? "text-2xl" : "",
|
||||
"text-8xl"
|
||||
`font-bold leading-none flex justify-between items-end`,
|
||||
typeText ? "text-3xl tracking-tight leading-10" : "text-7xl"
|
||||
)}
|
||||
>
|
||||
{KPI}
|
||||
{hasTrend && (
|
||||
<div className="text-green-600 bg-green-200 rounded-full">
|
||||
{trend}
|
||||
{trend && (
|
||||
<div className="flex items-center h-6 px-6 py-2 mb-2.5 text-sm font-light text-green-600 bg-green-200 rounded-full">
|
||||
{trend} %
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
useSubmissionSessions,
|
||||
} from "../../lib/submissionSessions";
|
||||
import { timeSince } from "../../lib/utils";
|
||||
import AnalyticsCard from "../layout/AnalyticsCard";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function ResultsAnalytics({ formId }) {
|
||||
const { submissionSessions, isLoadingSubmissionSessions } =
|
||||
@@ -22,56 +24,73 @@ export default function ResultsAnalytics({ formId }) {
|
||||
{
|
||||
id: "uniqueUsers",
|
||||
name: "Unique Users",
|
||||
stat: analytics.uniqueUsers,
|
||||
icon: UsersIcon,
|
||||
stat: analytics.uniqueUsers || "NaN",
|
||||
toolTipText: "placeholder",
|
||||
trend: "12",
|
||||
},
|
||||
{
|
||||
id: "totalSubmissions",
|
||||
name: "Total Submissions",
|
||||
stat: analytics.totalSubmissions,
|
||||
icon: InboxIcon,
|
||||
stat: analytics.totalSubmissions || "NaN",
|
||||
trend: "10",
|
||||
},
|
||||
{
|
||||
id: "uniqueUsers",
|
||||
id: "lastSubmission",
|
||||
name: "Last Submission",
|
||||
stat: timeSince(analytics.lastSubmissionAt) || "-",
|
||||
icon: ClockIcon,
|
||||
typeText: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
}, [analytics]);
|
||||
return (
|
||||
<main>
|
||||
<div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
<div className="max-w-5xl mx-auto sm:px-6 lg:px-8">
|
||||
<h2 className="mt-8 text-xl font-bold text-ui-gray-dark">Analytics</h2>
|
||||
<div>
|
||||
{stats ? (
|
||||
<dl className="grid grid-cols-1 gap-5 mt-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{stats.map((item) => (
|
||||
<div
|
||||
<AnalyticsCard
|
||||
key={item.id}
|
||||
className="relative px-4 bg-white rounded-lg shadow pt-5overflow-hidden sm:pt-6 sm:px-6"
|
||||
>
|
||||
<dt>
|
||||
<div className="absolute p-3 rounded-md bg-red-500">
|
||||
<item.icon
|
||||
className="w-6 h-6 text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="ml-16 text-sm font-medium text-gray-500 truncate">
|
||||
{item.name}
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="flex items-baseline ml-16 sm:pb-7">
|
||||
<p className="text-xl font-semibold text-gray-800">
|
||||
{item.stat}
|
||||
</p>
|
||||
</dd>
|
||||
</div>
|
||||
KPI={item.stat}
|
||||
label={item.name}
|
||||
toolTipText={item.toolTipText}
|
||||
typeText={item.typeText}
|
||||
trend={item.trend}
|
||||
/>
|
||||
))}
|
||||
</dl>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<h2 className="mt-16 text-xl font-bold text-ui-gray-dark">
|
||||
Optimize Form
|
||||
</h2>
|
||||
<div className="px-3 py-2 ml-2 text-xs text-green-800 rounded-sm bg-green-50">
|
||||
<p>coming soon</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-10 mt-8">
|
||||
<div className="relative p-8 bg-white rounded-md shadow-md h-60">
|
||||
<Image
|
||||
src="/../../img/drop-offs-v1.svg"
|
||||
alt="drop-off"
|
||||
objectFit="cover"
|
||||
layout="fill"
|
||||
className="rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative p-8 bg-white rounded-md shadow-md h-60">
|
||||
<Image
|
||||
src="/../../img/a-b-test-v1.svg"
|
||||
alt="drop-off"
|
||||
objectFit="cover"
|
||||
layout="fill"
|
||||
className="rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
import { SubmissionSummary } from "../../lib/types";
|
||||
import Loading from "../Loading";
|
||||
import TextResults from "./summary/TextResults";
|
||||
import { timeSince } from "../../lib/utils";
|
||||
import AnalyticsCard from "../layout/AnalyticsCard";
|
||||
|
||||
export default function ResultsSummary({ formId }) {
|
||||
const { submissionSessions, isLoadingSubmissionSessions } =
|
||||
@@ -27,20 +29,22 @@ export default function ResultsSummary({ formId }) {
|
||||
{
|
||||
id: "uniqueUsers",
|
||||
name: "Unique Users",
|
||||
stat: 10,
|
||||
icon: UsersIcon,
|
||||
stat: summary.uniqueUsers || "NaN",
|
||||
toolTipText: "placeholder",
|
||||
trend: "12",
|
||||
},
|
||||
{
|
||||
id: "totalSubmissions",
|
||||
name: "Total Submissions",
|
||||
stat: 10,
|
||||
icon: InboxIcon,
|
||||
stat: summary.totalSubmissions || "NaN",
|
||||
trend: "10",
|
||||
},
|
||||
{
|
||||
id: "uniqueUsers",
|
||||
id: "lastSubmission",
|
||||
name: "Last Submission",
|
||||
stat: 10,
|
||||
icon: ClockIcon,
|
||||
// stat: timeSince(analytics.lastSubmissionAt) || "-",
|
||||
stat: "NaN",
|
||||
typeText: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -52,49 +56,32 @@ export default function ResultsSummary({ formId }) {
|
||||
|
||||
return (
|
||||
<main className="bg-gray-50">
|
||||
<div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
<div>
|
||||
<dl className="grid grid-cols-1 gap-5 mt-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{stats.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="relative px-4 bg-white rounded-lg shadow pt-5overflow-hidden sm:pt-6 sm:px-6"
|
||||
>
|
||||
<dt>
|
||||
<div className="absolute p-3 rounded-md bg-red-500">
|
||||
<item.icon
|
||||
className="w-6 h-6 text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p className="ml-16 text-sm font-medium text-gray-500 truncate">
|
||||
{item.name}
|
||||
</p>
|
||||
</dt>
|
||||
<dd className="flex items-baseline ml-16 sm:pb-7">
|
||||
<p className="text-xl font-semibold text-gray-800">
|
||||
{item.stat}
|
||||
</p>
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
<hr className="my-8" />
|
||||
<div className="max-w-5xl mx-auto sm:px-6 lg:px-8">
|
||||
<h2 className="mt-8 text-xl font-bold text-ui-gray-dark">
|
||||
Responses Overview
|
||||
</h2>
|
||||
<dl className="grid grid-cols-1 gap-5 mt-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{stats.map((item) => (
|
||||
<AnalyticsCard
|
||||
key={item.id}
|
||||
KPI={item.stat}
|
||||
label={item.name}
|
||||
toolTipText={item.toolTipText}
|
||||
typeText={item.typeText}
|
||||
trend={item.trend}
|
||||
/>
|
||||
))}
|
||||
</dl>
|
||||
<div>
|
||||
{summary.pages.map(
|
||||
(page, pageIdx) =>
|
||||
page.type === "form" && (
|
||||
<div key={page.name}>
|
||||
<h2 className="text-xl font-bold text-gray-700">
|
||||
Page {pageIdx + 1}
|
||||
</h2>
|
||||
{page.elements.map((element) =>
|
||||
element.type === "text" || element.type === "textarea" ? (
|
||||
<TextResults element={element} />
|
||||
) : null
|
||||
)}
|
||||
<hr className="my-8" />
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -6,7 +6,7 @@ export default function TextResults({ element }) {
|
||||
<div className="flow-root px-8 my-4 mt-6 overflow-y-scroll text-center max-h-64">
|
||||
<ul className="-my-5 divide-y divide-ui-gray-light">
|
||||
{element.summary.map((answer) => (
|
||||
<li key={answer} className="py-5">
|
||||
<li key={answer} className="py-8">
|
||||
<div className="relative focus-within:ring-2 focus-within:ring-indigo-500">
|
||||
<h3 className="text-sm text-gray-700">
|
||||
{/* Extend touch target to entire panel */}
|
||||
|
||||
49
public/img/a-b-test-v1.svg
Normal file
49
public/img/a-b-test-v1.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 27 KiB |
12
public/img/drop-offs-v1.svg
Normal file
12
public/img/drop-offs-v1.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 40 KiB |
Reference in New Issue
Block a user