(
/>
);
-const renderProductRelevanceBar = (metrics) => (
-
-
-
-
Were the suggested products in this email relevant to you?
-
-
- {metrics.productRelevance.yesPercentage}% Positive
-
-
-
-
-
-
-
-
-
-
- {
- if (payload && payload.length) {
- const yesCount = payload[0].payload.yes;
- const noCount = payload[0].payload.no;
- const total = yesCount + noCount;
- const yesPercent = Math.round((yesCount / total) * 100);
- const noPercent = Math.round((noCount / total) * 100);
- return (
-
-
-
-
- Yes:
- {yesCount} ({yesPercent}%)
-
-
- No:
- {noCount} ({noPercent}%)
-
-
-
-
- );
- }
- return null;
- }}
- />
-
-
- {metrics.productRelevance.yesPercentage}%
-
-
-
-
-
-
-
-
Yes: {metrics.productRelevance.yesCount}
-
No: {metrics.productRelevance.noCount}
-
-
-
-);
-
-const renderLikelihoodChart = (metrics, responses) => {
- const likelihoodCounts = [1, 2, 3, 4, 5].map(rating => ({
- rating: rating.toString(),
- count: responses.items
- .filter(r => r.answers?.find(a => a.type === 'number')?.number === rating)
- .length
- }));
-
- return (
-
-
-
- How likely are you to place another order with us?
-
- {metrics.winback.averageRating}
- /5 avg
-
-
-
-
-
-
-
-
- {
- return value === "1" ? "Not at all likely" : value === "5" ? "Extremely likely" : "";
- }}
- textAnchor="middle"
- interval={0}
- height={50}
- />
-
- {
- if (payload && payload.length) {
- const { rating, count } = payload[0].payload;
- return (
-
-
- {rating} Rating: {count} responses
-
-
- );
- }
- return null;
- }}
- />
-
- {likelihoodCounts.map((_, index) => (
- |
- ))}
-
-
-
-
-
-
- );
-};
-
const TypeformDashboard = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -487,18 +327,55 @@ const TypeformDashboard = () => {
const metrics = loading ? null : calculateMetrics();
+ // Find the newest response across both forms
+ const getNewestResponse = () => {
+ if (!formData.form1.responses?.items?.length && !formData.form2.responses?.items?.length) return null;
+
+ const form1Latest = formData.form1.responses?.items[0]?.submitted_at;
+ const form2Latest = formData.form2.responses?.items[0]?.submitted_at;
+
+ if (!form1Latest) return form2Latest;
+ if (!form2Latest) return form1Latest;
+
+ return new Date(form1Latest) > new Date(form2Latest) ? form1Latest : form2Latest;
+ };
+
+ const newestResponse = getNewestResponse();
+
if (error) {
return (
-
-
- Error
- {error}
-
+
+
+
+ {error}
+
+
+
);
}
+ // Calculate likelihood counts for the chart
+ const likelihoodCounts = !loading && formData.form2.responses ? [1, 2, 3, 4, 5].map(rating => ({
+ rating: rating.toString(),
+ count: formData.form2.responses.items
+ .filter(r => r.answers?.find(a => a.type === 'number')?.number === rating)
+ .length
+ })) : [];
+
return (
-
+
+
+
+
+ Customer Surveys
+
+ {newestResponse && (
+
+ Newest response: {format(new Date(newestResponse), "MMM d, h:mm a")}
+
+ )}
+
+
{loading ? (
@@ -508,41 +385,195 @@ const TypeformDashboard = () => {
) : (
<>
- {renderProductRelevanceBar(metrics)}
- {renderLikelihoodChart(metrics, formData.form2.responses)}
-
+
-
-
-
-
- Reasons for Not Ordering
+
+
+
+ How likely are you to place another order with us?
+
+ {metrics.winback.averageRating}
+ /5 avg
+
+
-
-
-
- Reason
- Count
- %
-
-
-
- {metrics.winback.reasons.map((reason, index) => (
-
- {reason.reason}
- {reason.count}
- {reason.percentage}%
-
- ))}
-
-
+
+
+
+
+ {
+ return value === "1" ? "Not at all likely" : value === "5" ? "Extremely likely" : "";
+ }}
+ textAnchor="middle"
+ interval={0}
+ height={50}
+ className="text-muted-foreground"
+ />
+
+ {
+ if (payload && payload.length) {
+ const { rating, count } = payload[0].payload;
+ return (
+
+
+
+ {rating} Rating: {count} responses
+
+
+
+ );
+ }
+ return null;
+ }}
+ />
+
+ {likelihoodCounts.map((_, index) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+
+
Were the suggested products in this email relevant to you?
+
+
+ {metrics.productRelevance.yesPercentage}% Positive
+
+
+
+
+
+
+
+
+
+
+ {
+ if (payload && payload.length) {
+ const yesCount = payload[0].payload.yes;
+ const noCount = payload[0].payload.no;
+ const total = yesCount + noCount;
+ const yesPercent = Math.round((yesCount / total) * 100);
+ const noPercent = Math.round((noCount / total) * 100);
+ return (
+
+
+
+
+ Yes:
+ {yesCount} ({yesPercent}%)
+
+
+ No:
+ {noCount} ({noPercent}%)
+
+
+
+
+ );
+ }
+ return null;
+ }}
+ />
+
+
+ {metrics.productRelevance.yesPercentage}%
+
+
+
+
+
+
+
+
Yes: {metrics.productRelevance.yesCount}
+
No: {metrics.productRelevance.noCount}
+
-
-
-
+
+
+
+
+
+ Reasons for Not Ordering
+
+
+
+
+
+
+ Reason
+ Count
+ %
+
+
+
+ {metrics.winback.reasons.map((reason, index) => (
+
+ {reason.reason}
+ {reason.count}
+ {reason.percentage}%
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
>
)}