mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-29 19:10:50 -06:00
192 lines
5.7 KiB
TypeScript
192 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import { Loader2, UsersIcon } from "lucide-react";
|
|
import { useState } from "react";
|
|
import toast from "react-hot-toast";
|
|
|
|
import { cn } from "@formbricks/lib/cn";
|
|
import { formatDate, timeSinceDate } from "@formbricks/lib/time";
|
|
import { TSegment, ZSegmentFilters } from "@formbricks/types/segment";
|
|
import { TSurvey } from "@formbricks/types/surveys";
|
|
|
|
import { Modal } from "../Modal";
|
|
|
|
type 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 (
|
|
<div
|
|
key={segment.id}
|
|
className={cn(
|
|
"relative mt-1 grid h-16 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>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
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>;
|
|
};
|
|
|
|
const LoadSegmentModal = ({
|
|
open,
|
|
surveyId,
|
|
setOpen,
|
|
currentSegment,
|
|
segments,
|
|
setSegment,
|
|
setIsSegmentEditorOpen,
|
|
onSegmentLoad,
|
|
}: LoadSegmentModalProps) => {
|
|
const handleResetState = () => {
|
|
setOpen(false);
|
|
};
|
|
|
|
const segmentsArray = segments?.filter((segment) => !segment.isPrivate);
|
|
|
|
return (
|
|
<Modal
|
|
open={open}
|
|
setOpen={() => {
|
|
handleResetState();
|
|
}}
|
|
title="Load Segment"
|
|
size="lg">
|
|
<>
|
|
{!segmentsArray?.length ? (
|
|
<div className="group">
|
|
<div className="flex h-16 w-full flex-col items-center justify-center rounded-lg text-slate-700">
|
|
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">Segment</div>
|
|
<div className="col-span-1 hidden text-center sm:block">Updated at</div>
|
|
<div className="col-span-1 hidden text-center sm:block">Created at</div>
|
|
</div>
|
|
|
|
{segmentsArray.map((segment) => (
|
|
<SegmentDetail
|
|
segment={segment}
|
|
setIsSegmentEditorOpen={setIsSegmentEditorOpen}
|
|
setOpen={setOpen}
|
|
setSegment={setSegment}
|
|
onSegmentLoad={onSegmentLoad}
|
|
surveyId={surveyId}
|
|
currentSegment={currentSegment}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default LoadSegmentModal;
|