Feature/template update (#343)

* improve layout and information design of templates view

---------

Co-authored-by: moritzrengert <moritz@rengert.de>
This commit is contained in:
Johannes
2023-06-09 10:14:02 +02:00
committed by GitHub
parent fc6534fa19
commit 91d4b09453
10 changed files with 1379 additions and 438 deletions

View File

@@ -48,22 +48,6 @@ export default function TemplateList({ onTemplateClick, activeTemplate }: Templa
))}
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{/* <button
type="button"
onClick={() => {
onTemplateClick(activeTemplate);
setActiveTemplate(activeTemplate);
}}
className={cn(
activeTemplate?.name === customSurvey.name
? "ring-brand border-transparent ring-2"
: "hover:border-brand-dark border-dashed border-slate-300",
"duration-120 group relative rounded-lg border-2 bg-transparent p-8 transition-colors duration-150"
)}>
<PlusCircleIcon className="text-brand-dark h-8 w-8 transition-all duration-150 group-hover:scale-110" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700 ">{customSurvey.name}</h3>
<p className="text-left text-xs text-slate-600 ">{customSurvey.description}</p>
</button> */}
{templates
.filter((template) => selectedFilter === ALL_CATEGORY_NAME || template.category === selectedFilter)
.map((template: Template) => (

View File

@@ -28,7 +28,7 @@ import type { Template } from "@formbricks/types/templates";
const thankYouCardDefault = {
enabled: true,
headline: "Thank you!",
subheader: "We appreciate your time and insight.",
subheader: "We appreciate your feedback.",
};
export const customSurvey: Template = {

View File

@@ -133,13 +133,13 @@ export default function PreviewSurvey({
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -292,7 +292,7 @@ export default function LogicEditor({
{localSurvey.questions.map(
(question, idx) =>
idx !== questionIdx && (
<SelectItem key={question.id} value={question.id}>
<SelectItem key={question.id} value={question.id} title={question.headline}>
{idx + 1} - {truncate(question.headline, 14)}
</SelectItem>
)
@@ -317,7 +317,8 @@ export default function LogicEditor({
<div className="mt-2 flex items-center space-x-2">
<Button
id="logicJumps"
className="bg-slate-100 px-6 py-2 hover:bg-slate-50"
size="sm"
className="bg-slate-100 hover:bg-slate-50"
type="button"
name="logicJumps"
variant="secondary"

View File

@@ -14,6 +14,8 @@ import { SparklesIcon } from "@heroicons/react/24/solid";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { customSurvey, templates } from "./templates";
import { SplitIcon } from "lucide-react";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui";
type TemplateList = {
environmentId: string;
@@ -35,12 +37,6 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
const [categories, setCategories] = useState<Array<string>>([]);
/* useEffect(() => {
if (product && templates?.length) {
setActiveTemplate(customSurvey);
}
}, [product]); */
useEffect(() => {
const defaultCategories = [
/* ALL_CATEGORY_NAME, */
@@ -74,7 +70,7 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
return (
<main className="relative z-0 flex-1 overflow-y-auto px-6 pb-6 pt-3 focus:outline-none">
<div className="mb-6 flex flex-wrap space-x-2">
<div className="mb-6 flex flex-wrap gap-2">
{categories.map((category) => (
<button
key={category}
@@ -103,7 +99,7 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
activeTemplate?.name === customSurvey.name
? "ring-brand border-transparent ring-2"
: "hover:border-brand-dark border-dashed border-slate-300",
"duration-120 group relative rounded-lg border-2 bg-transparent p-8 transition-colors duration-150"
"duration-120 group relative rounded-lg border-2 bg-transparent p-6 transition-colors duration-150"
)}>
<PlusCircleIcon className="text-brand-dark h-8 w-8 transition-all duration-150 group-hover:scale-110" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700 ">{customSurvey.name}</h3>
@@ -138,13 +134,41 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
}}
key={template.name}
className={cn(
activeTemplate?.name === template.name && "ring-brand ring-2",
"duration-120 group relative cursor-pointer rounded-lg bg-white p-6 shadow transition-all duration-150 hover:scale-105"
activeTemplate?.name === template.name && "ring-2 ring-slate-400",
"duration-120 group relative cursor-pointer rounded-lg bg-white p-6 shadow transition-all duration-150 hover:scale-105"
)}>
<div className="absolute right-6 top-6 rounded border border-slate-300 bg-slate-50 px-1.5 py-0.5 text-xs text-slate-500">
{template.category}
<div className="flex">
<div
className={`rounded border px-1.5 py-0.5 text-xs ${
template.category === "Product Experience"
? "border-blue-300 bg-blue-50 text-blue-500"
: template.category === "Exploration"
? "border-pink-300 bg-pink-50 text-pink-500"
: template.category === "Growth"
? "border-orange-300 bg-orange-50 text-orange-500"
: template.category === "Increase Revenue"
? "border-emerald-300 bg-emerald-50 text-emerald-500"
: template.category === "Customer Success"
? "border-violet-300 bg-violet-50 text-violet-500"
: "border-slate-300 bg-slate-50 text-slate-500" // default color
}`}>
{template.category}
</div>
{template.preset.questions.some(
(question) => question.logic && question.logic.length > 0
) && (
<TooltipProvider delayDuration={80}>
<Tooltip>
<TooltipTrigger>
<div>
<SplitIcon className="ml-1.5 h-5 w-5 rounded border border-slate-300 bg-slate-50 p-0.5 text-slate-400" />
</div>
</TooltipTrigger>
<TooltipContent>This survey uses branching logic.</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
<template.icon className="h-8 w-8" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700">{template.name}</h3>
<p className="text-left text-xs text-slate-600">{template.description}</p>
{activeTemplate?.name === template.name && (

View File

@@ -72,13 +72,13 @@ export default function LinkSurvey({ survey }: LinkSurveyProps) {
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -101,13 +101,13 @@ export default function SurveyView({ config, survey, close, errorHandler }: Surv
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -72,21 +72,21 @@ export type LogicCondition =
export interface LogicBase {
condition: LogicCondition | undefined;
value: number | string | string[] | undefined;
value?: number | string | string[] | undefined;
destination: string | "end" | undefined;
}
export interface OpenTextLogic extends LogicBase {
condition: "submitted" | "skipped" | undefined;
value: undefined;
value?: undefined;
}
export interface MultipleChoiceSingleLogic extends LogicBase {
condition: "submitted" | "skipped" | "equals" | "notEquals" | undefined;
value: string;
value?: string;
}
export interface MultipleChoiceMultiLogic extends LogicBase {
condition: "submitted" | "skipped" | "includesAll" | "includesOne" | undefined;
value: string[];
value?: string[];
}
export interface NPSLogic extends LogicBase {
condition:
@@ -99,11 +99,11 @@ export interface NPSLogic extends LogicBase {
| "equals"
| "notEquals"
| undefined;
value: number;
value?: number;
}
export interface CTALogic extends LogicBase {
condition: "submitted" | "skipped" | undefined;
value: undefined;
value?: undefined;
}
export interface RatingLogic extends LogicBase {
condition:
@@ -116,7 +116,7 @@ export interface RatingLogic extends LogicBase {
| "equals"
| "notEquals"
| undefined;
value: number;
value?: number | string;
}
export type Logic =
| OpenTextLogic

View File

@@ -10,8 +10,8 @@ export type Objective =
export interface Template {
name: string;
icon: any;
description: string;
icon?: any;
category?: "Product Experience" | "Exploration" | "Growth" | "Increase Revenue" | "Customer Success";
objectives?: [Objective, Objective?, Objective?];
preset: {