mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-25 10:30:30 -06:00
feat: dev mode navbar in surveyEditor
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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'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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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} />
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user