Patch: Close survey on date can be set to past

Patch: Close survey on date can be set to past
This commit is contained in:
Johannes
2023-08-01 03:33:37 -05:00
committed by GitHub
3 changed files with 82 additions and 110 deletions

View File

@@ -4,11 +4,6 @@ import { useEnvironment } from "@/lib/environments/environments";
import { useProduct } from "@/lib/products/products";
import { TSurvey } from "@formbricks/types/v1/surveys";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Button,
DropdownMenu,
DropdownMenuContent,
@@ -22,13 +17,7 @@ import {
DropdownMenuTrigger,
ErrorComponent,
} from "@formbricks/ui";
import {
CheckCircleIcon,
PauseCircleIcon,
PlayCircleIcon,
PencilSquareIcon,
EllipsisHorizontalIcon,
} from "@heroicons/react/24/solid";
import { PencilSquareIcon, EllipsisHorizontalIcon } from "@heroicons/react/24/solid";
import SurveyStatusIndicator from "@/components/shared/SurveyStatusIndicator";
import { useSurveyMutation } from "@/lib/surveys/mutateSurveys";
import toast from "react-hot-toast";
@@ -36,6 +25,7 @@ import { useRouter } from "next/navigation";
import SuccessMessage from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/SuccessMessage";
import LinkSurveyShareButton from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/LinkModalButton";
import LoadingSpinner from "@/components/shared/LoadingSpinner";
import SurveyStatusDropdown from "@/components/shared/SurveyStatusDropdown";
interface SummaryHeaderProps {
surveyId: string;
@@ -48,6 +38,10 @@ const SummaryHeader = ({ surveyId, environmentId, survey }: SummaryHeaderProps)
const { environment, isLoadingEnvironment, isErrorEnvironment } = useEnvironment(environmentId);
const { triggerSurveyMutate } = useSurveyMutation(environmentId, surveyId);
const isCloseOnDateEnabled = survey.closeOnDate !== null;
const closeOnDate = survey.closeOnDate ? new Date(survey.closeOnDate) : null;
const isStatusChangeDisabled = (isCloseOnDateEnabled && closeOnDate && closeOnDate < new Date()) ?? false;
if (isLoadingProduct || isLoadingEnvironment) {
return <LoadingSpinner />;
}
@@ -64,53 +58,7 @@ const SummaryHeader = ({ surveyId, environmentId, survey }: SummaryHeaderProps)
<div className="hidden justify-end gap-x-1.5 sm:flex">
{survey.type === "link" && <LinkSurveyShareButton survey={survey} />}
{(environment?.widgetSetupCompleted || survey.type === "link") && survey?.status !== "draft" ? (
<Select
onValueChange={(value) => {
triggerSurveyMutate({ status: value })
.then(() => {
toast.success(
value === "inProgress"
? "Survey live"
: value === "paused"
? "Survey paused"
: value === "completed"
? "Survey completed"
: ""
);
router.refresh();
})
.catch((error) => {
toast.error(`Error: ${error.message}`);
});
}}>
<SelectTrigger className="w-[170px] bg-white py-6 md:w-[200px]">
<SelectValue>
<div className="flex items-center">
<SurveyStatusIndicator status={survey.status} environmentId={environmentId} />
<span className="ml-2 text-sm text-slate-700">
{survey.status === "inProgress" && "In-progress"}
{survey.status === "paused" && "Paused"}
{survey.status === "completed" && "Completed"}
{survey.status === "archived" && "Archived"}
</span>
</div>
</SelectValue>
</SelectTrigger>
<SelectContent className="bg-white">
<SelectItem className="group font-normal hover:text-slate-900" value="inProgress">
<PlayCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
In-progress
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="paused">
<PauseCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Paused
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="completed">
<CheckCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Completed
</SelectItem>
</SelectContent>
</Select>
<SurveyStatusDropdown environmentId={environmentId} surveyId={surveyId} />
) : null}
<Button
variant="darkCTA"
@@ -137,7 +85,9 @@ const SummaryHeader = ({ surveyId, environmentId, survey }: SummaryHeaderProps)
{(environment?.widgetSetupCompleted || survey.type === "link") && survey?.status !== "draft" ? (
<>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<DropdownMenuSubTrigger
disabled={isStatusChangeDisabled}
style={isStatusChangeDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}}>
<div className="flex items-center">
<SurveyStatusIndicator status={survey.status} environmentId={environmentId} />
<span className="ml-1 text-sm text-slate-700">

View File

@@ -11,6 +11,10 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@formbricks/ui";
import { CheckCircleIcon, PauseCircleIcon, PlayCircleIcon } from "@heroicons/react/24/solid";
import toast from "react-hot-toast";
@@ -35,6 +39,10 @@ export default function SurveyStatusDropdown({
return <ErrorComponent />;
}
const isCloseOnDateEnabled = survey.closeOnDate !== null;
const closeOnDate = survey.closeOnDate ? new Date(survey.closeOnDate) : null;
const isStatusChangeDisabled = (isCloseOnDateEnabled && closeOnDate && closeOnDate < new Date()) ?? false;
return (
<>
{survey.status === "draft" || survey.status === "archived" ? (
@@ -44,56 +52,69 @@ export default function SurveyStatusDropdown({
{survey.status === "archived" && <p className="text-sm italic text-slate-600">Archived</p>}
</div>
) : (
<Select
onValueChange={(value) => {
triggerSurveyMutate({ status: value })
.then(() => {
toast.success(
value === "inProgress"
? "Survey live"
: value === "paused"
? "Survey paused"
: value === "completed"
? "Survey completed"
: ""
);
})
.catch((error) => {
toast.error(`Error: ${error.message}`);
});
<TooltipProvider delayDuration={50}>
<Tooltip open={isStatusChangeDisabled ? undefined : false}>
<TooltipTrigger>
<Select
disabled={isStatusChangeDisabled}
onValueChange={(value) => {
triggerSurveyMutate({ status: value })
.then(() => {
toast.success(
value === "inProgress"
? "Survey live"
: value === "paused"
? "Survey paused"
: value === "completed"
? "Survey completed"
: ""
);
})
.catch((error) => {
toast.error(`Error: ${error.message}`);
});
if (updateLocalSurveyStatus)
updateLocalSurveyStatus(value as "draft" | "inProgress" | "paused" | "completed" | "archived");
}}>
<SelectTrigger className="w-[170px] bg-white py-6 md:w-[200px]">
<SelectValue>
<div className="flex items-center">
<SurveyStatusIndicator status={survey.status} environmentId={environmentId} />
<span className="ml-2 text-sm text-slate-700">
{survey.status === "draft" && "Survey draft"}
{survey.status === "inProgress" && "Collecting insights"}
{survey.status === "paused" && "Survey paused"}
{survey.status === "completed" && "Survey complete"}
{survey.status === "archived" && "Survey archived"}
</span>
</div>
</SelectValue>
</SelectTrigger>
<SelectContent className="bg-white">
<SelectItem className="group font-normal hover:text-slate-900" value="inProgress">
<PlayCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Collect insights
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="paused">
<PauseCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Pause Survey
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="completed">
<CheckCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Complete Survey
</SelectItem>
</SelectContent>
</Select>
if (updateLocalSurveyStatus)
updateLocalSurveyStatus(
value as "draft" | "inProgress" | "paused" | "completed" | "archived"
);
}}>
<SelectTrigger className="w-[170px] bg-white py-6 md:w-[200px]">
<SelectValue>
<div className="flex items-center">
<SurveyStatusIndicator status={survey.status} environmentId={environmentId} />
<span className="ml-2 text-sm text-slate-700">
{survey.status === "draft" && "Draft"}
{survey.status === "inProgress" && "In-progress"}
{survey.status === "paused" && "Paused"}
{survey.status === "completed" && "Completed"}
{survey.status === "archived" && "Archived"}
</span>
</div>
</SelectValue>
</SelectTrigger>
<SelectContent className="bg-white">
<SelectItem className="group font-normal hover:text-slate-900" value="inProgress">
<PlayCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
In-progress
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="paused">
<PauseCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Paused
</SelectItem>
<SelectItem className="group font-normal hover:text-slate-900" value="completed">
<CheckCircleIcon className="-mt-1 mr-1 inline h-5 w-5 text-slate-500 group-hover:text-slate-800" />
Completed
</SelectItem>
</SelectContent>
</Select>
</TooltipTrigger>
<TooltipContent>
To update the survey status, update the &ldquo;Close
<br /> survey on date&rdquo; setting in the Response Options.
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</>
);

View File

@@ -8,6 +8,7 @@ import Button from "./Button";
import { Calendar } from "./Calendar";
import { useRef } from "react";
import { SelectSingleEventHandler } from "react-day-picker";
import { addDays } from "date-fns";
export function DatePicker({
date,
@@ -44,7 +45,7 @@ export function DatePicker({
mode="single"
selected={formattedDate}
disabled={{
before: new Date(),
before: addDays(new Date(), 1),
}}
onSelect={handleDateSelect}
initialFocus