mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-28 20:49:34 -05:00
refactors
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
"use server";
|
||||
|
||||
// eslint-disable-next-line
|
||||
// TODO: remove revalidatePath and use revalidateTag instead once this has become stable: https://nextjs.org/docs/app/api-reference/directives/use-cache#usage
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { z } from "zod";
|
||||
import { ZWidgetLayout } from "@formbricks/types/analysis";
|
||||
|
||||
@@ -4,7 +4,9 @@ import { Loader2Icon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { getChartsAction } from "@/modules/ee/analysis/charts/actions";
|
||||
import { addChartToDashboardAction } from "@/modules/ee/analysis/dashboards/actions";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/modules/ui/components/alert";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import {
|
||||
@@ -17,7 +19,6 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/modules/ui/components/dialog";
|
||||
import { MultiSelect } from "@/modules/ui/components/multi-select";
|
||||
import { addChartToDashboardAction } from "../actions";
|
||||
|
||||
interface AddExistingChartsDialogProps {
|
||||
open: boolean;
|
||||
@@ -59,7 +60,8 @@ export function AddExistingChartsDialog({
|
||||
const availableCharts = result.data.filter((chart) => !existingChartIds.includes(chart.id));
|
||||
setChartOptions(availableCharts.map((chart) => ({ value: chart.id, label: chart.name })));
|
||||
} else {
|
||||
toast.error(result?.serverError || t("environments.analysis.dashboards.charts_load_failed"));
|
||||
const errorMessage = getFormattedErrorMessage(result);
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch {
|
||||
toast.error(t("environments.analysis.dashboards.charts_load_failed"));
|
||||
|
||||
@@ -6,9 +6,9 @@ import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { createDashboardAction } from "@/modules/ee/analysis/dashboards/actions";
|
||||
import { CreateDashboardDialog } from "@/modules/ee/analysis/dashboards/components/create-dashboard-dialog";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { createDashboardAction } from "../actions";
|
||||
import { CreateDashboardDialog } from "./create-dashboard-dialog";
|
||||
|
||||
interface CreateDashboardButtonProps {
|
||||
environmentId: string;
|
||||
|
||||
@@ -5,10 +5,11 @@ import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { deleteDashboardAction } from "@/modules/ee/analysis/dashboards/actions";
|
||||
import { AddExistingChartsDialog } from "@/modules/ee/analysis/dashboards/components/add-existing-charts-dialog";
|
||||
import { DeleteDialog } from "@/modules/ui/components/delete-dialog";
|
||||
import { IconBar } from "@/modules/ui/components/iconbar";
|
||||
import { deleteDashboardAction } from "../actions";
|
||||
import { AddExistingChartsDialog } from "./add-existing-charts-dialog";
|
||||
|
||||
interface DashboardControlBarProps {
|
||||
environmentId: string;
|
||||
@@ -51,12 +52,11 @@ export const DashboardControlBar = ({
|
||||
router.push(`/environments/${environmentId}/analysis/dashboards`);
|
||||
toast.success(t("environments.analysis.dashboards.delete_success"));
|
||||
} else {
|
||||
toast.error(result?.serverError || t("environments.analysis.dashboards.delete_failed"));
|
||||
const errorMessage = getFormattedErrorMessage(result);
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : t("environments.analysis.dashboards.delete_failed");
|
||||
toast.error(message);
|
||||
} catch {
|
||||
toast.error(t("environments.analysis.dashboards.delete_failed"));
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setDeleteDialogOpen(false);
|
||||
|
||||
@@ -10,16 +10,17 @@ import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "react-resizable/css/styles.css";
|
||||
import type { TChartQuery } from "@formbricks/types/analysis";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { DashboardControlBar } from "@/modules/ee/analysis/dashboards/components/dashboard-control-bar";
|
||||
import { DashboardPageHeader } from "@/modules/ee/analysis/dashboards/components/dashboard-page-header";
|
||||
import { DashboardWidget } from "@/modules/ee/analysis/dashboards/components/dashboard-widget";
|
||||
import { DashboardWidgetData } from "@/modules/ee/analysis/dashboards/components/dashboard-widget-data";
|
||||
import { DashboardWidgetSkeleton } from "@/modules/ee/analysis/dashboards/components/dashboard-widget-skeleton";
|
||||
import type { TChartDataRow, TDashboardDetail, TDashboardWidget } from "@/modules/ee/analysis/types/analysis";
|
||||
import { EmptyState } from "@/modules/ui/components/empty-state";
|
||||
import { GoBackButton } from "@/modules/ui/components/go-back-button";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { updateDashboardAction, updateWidgetLayoutsAction } from "../actions";
|
||||
import { DashboardControlBar } from "./dashboard-control-bar";
|
||||
import { DashboardPageHeader } from "./dashboard-page-header";
|
||||
import { DashboardWidget } from "./dashboard-widget";
|
||||
import { DashboardWidgetData } from "./dashboard-widget-data";
|
||||
import { DashboardWidgetSkeleton } from "./dashboard-widget-skeleton";
|
||||
|
||||
const ROW_HEIGHT = 80;
|
||||
|
||||
@@ -30,7 +31,7 @@ interface DashboardDetailClientProps {
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
function widgetsToLayout(widgets: TDashboardWidget[]): LayoutItem[] {
|
||||
const widgetsToLayout = (widgets: TDashboardWidget[]): LayoutItem[] => {
|
||||
return widgets.map((widget) => ({
|
||||
i: widget.id,
|
||||
x: widget.layout.x,
|
||||
@@ -42,9 +43,9 @@ function widgetsToLayout(widgets: TDashboardWidget[]): LayoutItem[] {
|
||||
maxW: 12,
|
||||
maxH: 8,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
function widgetLayoutsChanged(current: TDashboardWidget[], original: TDashboardWidget[]): boolean {
|
||||
const widgetLayoutsChanged = (current: TDashboardWidget[], original: TDashboardWidget[]): boolean => {
|
||||
if (current.length !== original.length) return true;
|
||||
return current.some((widget, i) => {
|
||||
const orig = original[i];
|
||||
@@ -57,9 +58,9 @@ function widgetLayoutsChanged(current: TDashboardWidget[], original: TDashboardW
|
||||
widget.order !== orig.order
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function applyLayoutToWidgets(widgets: TDashboardWidget[], newLayout: Layout): TDashboardWidget[] {
|
||||
const applyLayoutToWidgets = (widgets: TDashboardWidget[], newLayout: Layout): TDashboardWidget[] => {
|
||||
let changed = false;
|
||||
const updated = widgets.map((widget) => {
|
||||
const layoutItem = newLayout.find((l) => l.i === widget.id);
|
||||
@@ -87,33 +88,35 @@ function applyLayoutToWidgets(widgets: TDashboardWidget[], newLayout: Layout): T
|
||||
});
|
||||
|
||||
return changed ? updated : widgets;
|
||||
}
|
||||
};
|
||||
|
||||
const MemoizedWidgetContent = memo(function WidgetContent({
|
||||
widget,
|
||||
dataPromise,
|
||||
}: Readonly<{
|
||||
widget: TDashboardWidget;
|
||||
dataPromise?: Promise<{ data: TChartDataRow[]; query: TChartQuery } | { error: string }>;
|
||||
}>) {
|
||||
if (widget.chart && dataPromise) {
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<Delay ms={200}>
|
||||
<DashboardWidgetSkeleton />
|
||||
</Delay>
|
||||
}>
|
||||
<DashboardWidgetData
|
||||
dataPromise={dataPromise}
|
||||
chartType={widget.chart.type}
|
||||
query={widget.chart.query}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
const MemoizedWidgetContent = memo(
|
||||
({
|
||||
widget,
|
||||
dataPromise,
|
||||
}: Readonly<{
|
||||
widget: TDashboardWidget;
|
||||
dataPromise?: Promise<{ data: TChartDataRow[]; query: TChartQuery } | { error: string }>;
|
||||
}>) => {
|
||||
if (widget.chart && dataPromise) {
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<Delay ms={200}>
|
||||
<DashboardWidgetSkeleton />
|
||||
</Delay>
|
||||
}>
|
||||
<DashboardWidgetData
|
||||
dataPromise={dataPromise}
|
||||
chartType={widget.chart.type}
|
||||
query={widget.chart.query}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
return <DashboardWidgetSkeleton />;
|
||||
}
|
||||
return <DashboardWidgetSkeleton />;
|
||||
});
|
||||
);
|
||||
|
||||
const MemoizedWidgetItem = memo(function WidgetItem({
|
||||
widget,
|
||||
@@ -143,7 +146,7 @@ export function DashboardDetailClient({
|
||||
}: Readonly<DashboardDetailClientProps>) {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { width, containerRef, mounted } = useContainerWidth({ initialWidth: 1200 });
|
||||
const { width, containerRef, mounted } = useContainerWidth();
|
||||
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -199,9 +202,8 @@ export function DashboardDetailClient({
|
||||
});
|
||||
|
||||
if (!dashboardResult?.data) {
|
||||
toast.error(
|
||||
dashboardResult?.serverError || t("environments.analysis.dashboards.dashboard_update_failed")
|
||||
);
|
||||
const errorMessage = getFormattedErrorMessage(dashboardResult);
|
||||
toast.error(errorMessage);
|
||||
setIsSaving(false);
|
||||
return;
|
||||
}
|
||||
@@ -221,9 +223,8 @@ export function DashboardDetailClient({
|
||||
});
|
||||
|
||||
if (!widgetsResult?.data) {
|
||||
toast.error(
|
||||
widgetsResult?.serverError || t("environments.analysis.dashboards.widget_layouts_save_failed")
|
||||
);
|
||||
const errorMessage = getFormattedErrorMessage(widgetsResult);
|
||||
toast.error(errorMessage);
|
||||
setIsSaving(false);
|
||||
return;
|
||||
}
|
||||
@@ -235,10 +236,8 @@ export function DashboardDetailClient({
|
||||
setDraftWidgets(null);
|
||||
setIsEditing(false);
|
||||
});
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : t("environments.analysis.dashboards.dashboard_save_failed");
|
||||
toast.error(message);
|
||||
} catch {
|
||||
toast.error(t("environments.analysis.dashboards.dashboard_save_failed"));
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { CopyIcon, MoreVertical, SquarePenIcon, TrashIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
@@ -44,9 +43,8 @@ export const DashboardDropdownMenu = ({
|
||||
toast.success(t("environments.analysis.dashboards.duplicate_success"));
|
||||
router.refresh();
|
||||
} else {
|
||||
toast.error(
|
||||
getFormattedErrorMessage(result) || t("environments.analysis.dashboards.duplicate_failed")
|
||||
);
|
||||
const errorMessage = getFormattedErrorMessage(result);
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch {
|
||||
toast.error(t("environments.analysis.dashboards.duplicate_failed"));
|
||||
@@ -64,7 +62,8 @@ export const DashboardDropdownMenu = ({
|
||||
toast.success(t("environments.analysis.dashboards.delete_success"));
|
||||
router.refresh();
|
||||
} else {
|
||||
toast.error(getFormattedErrorMessage(result) || t("environments.analysis.dashboards.delete_failed"));
|
||||
const errorMessage = getFormattedErrorMessage(result);
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch {
|
||||
toast.error(t("environments.analysis.dashboards.delete_failed"));
|
||||
@@ -84,10 +83,13 @@ export const DashboardDropdownMenu = ({
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="inline-block w-auto min-w-max" align="end">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem icon={<SquarePenIcon className="size-4" />} asChild>
|
||||
<Link href={`/environments/${environmentId}/analysis/dashboards/${dashboardId}`}>
|
||||
{t("common.edit")}
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
icon={<SquarePenIcon className="size-4" />}
|
||||
onClick={() => {
|
||||
setIsDropDownOpen(false);
|
||||
router.push(`/environments/${environmentId}/analysis/dashboards/${dashboardId}`);
|
||||
}}>
|
||||
{t("common.edit")}
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
|
||||
Reference in New Issue
Block a user