mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-23 21:59:28 -05:00
a5fa876aa3
Co-authored-by: Piyush Gupta <piyushguptaa2z123@gmail.com> Co-authored-by: Piyush Gupta <56182734+gupta-piyush19@users.noreply.github.com> Co-authored-by: Victor Hugo dos Santos <115753265+victorvhs017@users.noreply.github.com> Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com> Co-authored-by: Matti Nannt <matti@formbricks.com> Co-authored-by: Matti Nannt <mail@matthiasnannt.com> Co-authored-by: Johannes <johannes@formbricks.com> Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
195 lines
6.2 KiB
TypeScript
195 lines
6.2 KiB
TypeScript
"use client";
|
|
|
|
import { Loader2, UsersIcon } from "lucide-react";
|
|
import { useState } from "react";
|
|
import toast from "react-hot-toast";
|
|
import { useTranslation } from "react-i18next";
|
|
import { TSegment, ZSegmentFilters } from "@formbricks/types/segment";
|
|
import { TSurvey } from "@formbricks/types/surveys/types";
|
|
import { cn } from "@/lib/cn";
|
|
import { formatDate, timeSinceDate } from "@/lib/time";
|
|
import { Dialog, DialogBody, DialogContent, DialogHeader, DialogTitle } from "@/modules/ui/components/dialog";
|
|
|
|
interface SegmentDetailProps {
|
|
segment: TSegment;
|
|
setSegment: (segment: TSegment) => void;
|
|
setOpen: (open: boolean) => void;
|
|
setIsSegmentEditorOpen: (isOpen: boolean) => void;
|
|
onSegmentLoad: (surveyId: string, segmentId: string) => Promise<TSurvey>;
|
|
surveyId: string;
|
|
currentSegment: TSegment;
|
|
}
|
|
|
|
const SegmentDetail = ({
|
|
segment,
|
|
setIsSegmentEditorOpen,
|
|
setOpen,
|
|
setSegment,
|
|
onSegmentLoad,
|
|
surveyId,
|
|
currentSegment,
|
|
}: SegmentDetailProps) => {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const handleLoadNewSegment = async (segmentId: string) => {
|
|
try {
|
|
if (currentSegment.id === segmentId) {
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
const updatedSurvey = await onSegmentLoad(surveyId, segmentId);
|
|
|
|
if (!updatedSurvey?.id || !updatedSurvey?.segment) {
|
|
toast.error("Error loading survey");
|
|
setIsLoading(false);
|
|
setIsSegmentEditorOpen(false);
|
|
setOpen(false);
|
|
return;
|
|
}
|
|
|
|
const parsedFilters = ZSegmentFilters.safeParse(updatedSurvey?.segment?.filters);
|
|
|
|
if (!parsedFilters.success) {
|
|
toast.error("Error loading survey");
|
|
setIsLoading(false);
|
|
setIsSegmentEditorOpen(false);
|
|
setOpen(false);
|
|
return;
|
|
}
|
|
|
|
setSegment({
|
|
...updatedSurvey.segment,
|
|
description: updatedSurvey.segment.description || "",
|
|
filters: parsedFilters.data,
|
|
surveys: updatedSurvey.segment.surveys,
|
|
});
|
|
|
|
setIsLoading(false);
|
|
} catch (err: any) {
|
|
setIsLoading(false);
|
|
toast.error(err.message);
|
|
setOpen(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<button
|
|
key={segment.id}
|
|
className={cn(
|
|
"relative mt-1 grid h-16 w-full cursor-pointer grid-cols-5 content-center rounded-lg hover:bg-slate-100",
|
|
currentSegment.id === segment.id && "pointer-events-none bg-slate-100 opacity-60"
|
|
)}
|
|
onClick={async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
await handleLoadNewSegment(segment.id);
|
|
setIsLoading(false);
|
|
} catch (err) {
|
|
setIsLoading(false);
|
|
}
|
|
}}>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-slate-50 opacity-80">
|
|
<Loader2 className="h-6 w-6 animate-spin" />
|
|
</div>
|
|
)}
|
|
<div className="col-span-3 flex items-center pl-6 text-sm">
|
|
<div className="flex items-center gap-4">
|
|
<div className="ph-no-capture h-8 w-8 flex-shrink-0 text-slate-700">
|
|
<UsersIcon className="h-5 w-5" />
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<div className="ph-no-capture font-medium text-slate-900">{segment.title}</div>
|
|
<div className="ph-no-capture text-xs font-medium text-slate-500">{segment.description}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="whitespace-wrap col-span-1 my-auto hidden text-center text-sm text-slate-500 sm:block">
|
|
<div className="ph-no-capture text-slate-900">{timeSinceDate(segment.updatedAt)}</div>
|
|
</div>
|
|
|
|
<div className="whitespace-wrap col-span-1 my-auto hidden text-center text-sm text-slate-500 sm:block">
|
|
<div className="ph-no-capture text-slate-900">{formatDate(segment.createdAt)}</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
};
|
|
|
|
type LoadSegmentModalProps = {
|
|
open: boolean;
|
|
setOpen: (open: boolean) => void;
|
|
surveyId: string;
|
|
currentSegment: TSegment;
|
|
segments: TSegment[];
|
|
setSegment: (segment: TSegment) => void;
|
|
setIsSegmentEditorOpen: (isOpen: boolean) => void;
|
|
onSegmentLoad: (surveyId: string, segmentId: string) => Promise<TSurvey>;
|
|
};
|
|
|
|
export const LoadSegmentModal = ({
|
|
open,
|
|
surveyId,
|
|
setOpen,
|
|
currentSegment,
|
|
segments,
|
|
setSegment,
|
|
setIsSegmentEditorOpen,
|
|
onSegmentLoad,
|
|
}: LoadSegmentModalProps) => {
|
|
const handleResetState = () => {
|
|
setOpen(false);
|
|
};
|
|
const { t } = useTranslation();
|
|
const segmentsArray = segments?.filter((segment) => !segment.isPrivate);
|
|
|
|
return (
|
|
<Dialog
|
|
open={open}
|
|
onOpenChange={(open) => {
|
|
if (!open) {
|
|
handleResetState();
|
|
}
|
|
}}>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>{t("environments.surveys.edit.load_segment")}</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<DialogBody>
|
|
{!segmentsArray?.length ? (
|
|
<div className="group">
|
|
<div className="flex h-16 w-full flex-col items-center justify-center rounded-md text-slate-700">
|
|
{t("environments.surveys.edit.you_have_not_created_a_segment_yet")}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="flex flex-col">
|
|
<div>
|
|
<div className="grid h-12 grid-cols-5 content-center rounded-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
|
|
<div className="col-span-3 pl-6">{t("common.segment")}</div>
|
|
<div className="col-span-1 hidden text-center sm:block">{t("common.updated_at")}</div>
|
|
<div className="col-span-1 hidden text-center sm:block">{t("common.created_at")}</div>
|
|
</div>
|
|
|
|
{segmentsArray.map((segment) => (
|
|
<SegmentDetail
|
|
key={segment.id}
|
|
segment={segment}
|
|
setIsSegmentEditorOpen={setIsSegmentEditorOpen}
|
|
setOpen={setOpen}
|
|
setSegment={setSegment}
|
|
onSegmentLoad={onSegmentLoad}
|
|
surveyId={surveyId}
|
|
currentSegment={currentSegment}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</DialogBody>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|