feat: dev mode navbar in surveyEditor

This commit is contained in:
ShubhamPalriwala
2023-08-25 11:14:33 +05:30
parent 9f6c40fd42
commit fbd42a572e
3 changed files with 116 additions and 95 deletions

View File

@@ -1,7 +1,6 @@
"use client";
import LoadingSpinner from "@/components/shared/LoadingSpinner";
import { useEnvironment } from "@/lib/environments/environments";
import { useProduct } from "@/lib/products/products";
import { useSurvey } from "@/lib/surveys/surveys";
import type { Survey } from "@formbricks/types/surveys";
@@ -12,20 +11,25 @@ import QuestionsAudienceTabs from "./QuestionsSettingsTabs";
import QuestionsView from "./QuestionsView";
import SettingsView from "./SettingsView";
import SurveyMenuBar from "./SurveyMenuBar";
import { TEnvironment } from "@formbricks/types/v1/environment";
interface SurveyEditorProps {
environmentId: string;
surveyId: string;
environment: TEnvironment;
}
export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorProps): JSX.Element {
export default function SurveyEditor({
environmentId,
surveyId,
environment,
}: SurveyEditorProps): JSX.Element {
const [activeView, setActiveView] = useState<"questions" | "settings">("questions");
const [activeQuestionId, setActiveQuestionId] = useState<string | null>(null);
const [localSurvey, setLocalSurvey] = useState<Survey | null>();
const [invalidQuestions, setInvalidQuestions] = useState<String[] | null>(null);
const { survey, isLoadingSurvey, isErrorSurvey } = useSurvey(environmentId, surveyId, true);
const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId);
const { environment, isLoadingEnvironment, isErrorEnvironment } = useEnvironment(environmentId);
useEffect(() => {
if (survey) {
@@ -37,11 +41,11 @@ export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorPr
}
}, [survey]);
if (isLoadingSurvey || isLoadingProduct || isLoadingEnvironment || !localSurvey) {
if (isLoadingSurvey || isLoadingProduct || !localSurvey) {
return <LoadingSpinner />;
}
if (isErrorSurvey || isErrorProduct || isErrorEnvironment) {
if (isErrorSurvey || isErrorProduct) {
return <ErrorComponent />;
}
@@ -52,6 +56,7 @@ export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorPr
localSurvey={localSurvey}
survey={survey}
environmentId={environmentId}
environment={environment}
activeId={activeView}
setActiveId={setActiveView}
setInvalidQuestions={setInvalidQuestions}

View File

@@ -14,12 +14,14 @@ import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { validateQuestion } from "./Validation";
import { TEnvironment } from "@formbricks/types/v1/environment";
interface SurveyMenuBarProps {
localSurvey: Survey;
survey: Survey;
setLocalSurvey: (survey: Survey) => void;
environmentId: string;
environment: TEnvironment;
activeId: "questions" | "settings";
setActiveId: (id: "questions" | "settings") => void;
setInvalidQuestions: (invalidQuestions: String[]) => void;
@@ -29,6 +31,7 @@ export default function SurveyMenuBar({
localSurvey,
survey,
environmentId,
environment,
setLocalSurvey,
activeId,
setActiveId,
@@ -159,101 +162,110 @@ export default function SurveyMenuBar({
};
return (
<div className="border-b border-slate-200 bg-white px-5 py-3 sm:flex sm:items-center sm:justify-between">
<div className="flex items-center space-x-2 whitespace-nowrap">
<Button
variant="secondary"
StartIcon={ArrowLeftIcon}
onClick={() => {
handleBack();
}}>
Back
</Button>
<p className="hidden pl-4 font-semibold md:block">{product.name} / </p>
<Input
defaultValue={localSurvey.name}
onChange={(e) => {
const updatedSurvey = { ...localSurvey, name: e.target.value };
setLocalSurvey(updatedSurvey);
}}
className="w-72 border-white hover:border-slate-200 "
/>
</div>
{!!localSurvey?.responseRate && (
<div className="mx-auto flex items-center rounded-full border border-amber-200 bg-amber-100 p-2 text-amber-700 shadow-sm">
<ExclamationTriangleIcon className=" h-5 w-5 text-amber-400" />
<p className="max-w-[90%] pl-1 text-xs lg:text-sm">
This survey received responses. To keep the data consistent, make changes with caution.
</p>
</div>
<>
{environment?.type === "development" && (
<nav className="top-0 z-10 w-full border-b border-slate-200 bg-white">
<div className="h-6 w-full bg-[#A33700] p-0.5 text-center text-sm text-white">
You&apos;re in development mode. Use it to test surveys, actions and attributes.
</div>
</nav>
)}
<div className="mt-3 flex sm:ml-4 sm:mt-0">
<div className="mr-4 flex items-center">
<SurveyStatusDropdown
surveyId={localSurvey.id}
environmentId={environmentId}
updateLocalSurveyStatus={updateLocalSurveyStatus}
<div className="border-b border-slate-200 bg-white px-5 py-3 sm:flex sm:items-center sm:justify-between">
<div className="flex items-center space-x-2 whitespace-nowrap">
<Button
variant="secondary"
StartIcon={ArrowLeftIcon}
onClick={() => {
handleBack();
}}>
Back
</Button>
<p className="hidden pl-4 font-semibold md:block">{product.name} / </p>
<Input
defaultValue={localSurvey.name}
onChange={(e) => {
const updatedSurvey = { ...localSurvey, name: e.target.value };
setLocalSurvey(updatedSurvey);
}}
className="w-72 border-white hover:border-slate-200 "
/>
</div>
<Button
variant={localSurvey.status === "draft" ? "secondary" : "darkCTA"}
className="mr-3"
loading={isMutatingSurvey}
onClick={() => saveSurveyAction()}>
Save
</Button>
{localSurvey.status === "draft" && audiencePrompt && (
<Button
variant="darkCTA"
onClick={() => {
setAudiencePrompt(false);
setActiveId("settings");
}}
EndIcon={Cog8ToothIcon}>
Continue to Settings
</Button>
{!!localSurvey?.responseRate && (
<div className="mx-auto flex items-center rounded-full border border-amber-200 bg-amber-100 p-2 text-amber-700 shadow-sm">
<ExclamationTriangleIcon className=" h-5 w-5 text-amber-400" />
<p className="max-w-[90%] pl-1 text-xs lg:text-sm">
This survey received responses. To keep the data consistent, make changes with caution.
</p>
</div>
)}
{localSurvey.status === "draft" && !audiencePrompt && (
<div className="mt-3 flex sm:ml-4 sm:mt-0">
<div className="mr-4 flex items-center">
<SurveyStatusDropdown
surveyId={localSurvey.id}
environmentId={environmentId}
updateLocalSurveyStatus={updateLocalSurveyStatus}
/>
</div>
<Button
disabled={
localSurvey.type === "web" &&
localSurvey.triggers &&
(localSurvey.triggers[0] === "" || localSurvey.triggers.length === 0)
}
variant="darkCTA"
variant={localSurvey.status === "draft" ? "secondary" : "darkCTA"}
className="mr-3"
loading={isMutatingSurvey}
onClick={async () => {
if (!validateSurvey(localSurvey)) {
return;
}
await triggerSurveyMutate({ ...localSurvey, status: "inProgress" });
router.push(`/environments/${environmentId}/surveys/${localSurvey.id}/summary?success=true`);
}}>
Publish
onClick={() => saveSurveyAction()}>
Save
</Button>
)}
{localSurvey.status === "draft" && audiencePrompt && (
<Button
variant="darkCTA"
onClick={() => {
setAudiencePrompt(false);
setActiveId("settings");
}}
EndIcon={Cog8ToothIcon}>
Continue to Settings
</Button>
)}
{localSurvey.status === "draft" && !audiencePrompt && (
<Button
disabled={
localSurvey.type === "web" &&
localSurvey.triggers &&
(localSurvey.triggers[0] === "" || localSurvey.triggers.length === 0)
}
variant="darkCTA"
loading={isMutatingSurvey}
onClick={async () => {
if (!validateSurvey(localSurvey)) {
return;
}
await triggerSurveyMutate({ ...localSurvey, status: "inProgress" });
router.push(`/environments/${environmentId}/surveys/${localSurvey.id}/summary?success=true`);
}}>
Publish
</Button>
)}
</div>
<DeleteDialog
deleteWhat="Draft"
open={isDeleteDialogOpen}
setOpen={setDeleteDialogOpen}
onDelete={() => deleteSurveyAction(localSurvey)}
text="Do you want to delete this draft?"
useSaveInsteadOfCancel={true}
onSave={() => saveSurveyAction(true)}
/>
<AlertDialog
confirmWhat="Survey changes"
open={isConfirmDialogOpen}
setOpen={setConfirmDialogOpen}
onDiscard={() => {
setConfirmDialogOpen(false);
router.back();
}}
text="You have unsaved changes in your survey. Would you like to save them before leaving?"
useSaveInsteadOfCancel={true}
onSave={() => saveSurveyAction(true)}
/>
</div>
<DeleteDialog
deleteWhat="Draft"
open={isDeleteDialogOpen}
setOpen={setDeleteDialogOpen}
onDelete={() => deleteSurveyAction(localSurvey)}
text="Do you want to delete this draft?"
useSaveInsteadOfCancel={true}
onSave={() => saveSurveyAction(true)}
/>
<AlertDialog
confirmWhat="Survey changes"
open={isConfirmDialogOpen}
setOpen={setConfirmDialogOpen}
onDiscard={() => {
setConfirmDialogOpen(false);
router.back();
}}
text="You have unsaved changes in your survey. Would you like to save them before leaving?"
useSaveInsteadOfCancel={true}
onSave={() => saveSurveyAction(true)}
/>
</div>
</>
);
}

View File

@@ -1,5 +1,9 @@
import SurveyEditor from "./SurveyEditor";
import { getEnvironment } from "@formbricks/lib/services/environment";
export default function SurveysEditPage({ params }) {
return <SurveyEditor environmentId={params.environmentId} surveyId={params.surveyId} />;
export default async function SurveysEditPage({ params }) {
const environment = await getEnvironment(params.environmentId);
return (
<SurveyEditor environmentId={params.environmentId} surveyId={params.surveyId} environment={environment} />
);
}