mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 02:10:12 -06:00
chore: remove swr from dependencies (#1407)
This commit is contained in:
@@ -11,9 +11,17 @@ import { Badge } from "@formbricks/ui/Badge";
|
||||
import { ComputerDesktopIcon, LinkIcon, PlusIcon } from "@heroicons/react/24/solid";
|
||||
import Link from "next/link";
|
||||
import { generateSurveySingleUseId } from "@/app/lib/singleUseSurveys";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
|
||||
export default async function SurveysList({ environmentId }: { environmentId: string }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
const product = await getProductByEnvironmentId(environmentId);
|
||||
|
||||
if (!session) {
|
||||
throw new Error("Session not found");
|
||||
}
|
||||
|
||||
if (!product) {
|
||||
throw new Error("Product not found");
|
||||
}
|
||||
@@ -28,7 +36,14 @@ export default async function SurveysList({ environmentId }: { environmentId: st
|
||||
const otherEnvironment = environments.find((e) => e.type !== environment.type)!;
|
||||
|
||||
if (surveys.length === 0) {
|
||||
return <SurveyStarter environmentId={environmentId} environment={environment} product={product} />;
|
||||
return (
|
||||
<SurveyStarter
|
||||
environmentId={environmentId}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={session.user}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,15 +9,18 @@ import { TTemplate } from "@formbricks/types/templates";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
|
||||
export default function SurveyStarter({
|
||||
environmentId,
|
||||
environment,
|
||||
product,
|
||||
profile,
|
||||
}: {
|
||||
environmentId: string;
|
||||
environment: TEnvironment;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
}) {
|
||||
const [isCreateSurveyLoading, setIsCreateSurveyLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
@@ -56,6 +59,7 @@ export default function SurveyStarter({
|
||||
}}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={profile}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -10,17 +10,20 @@ import TemplateList from "./TemplateList";
|
||||
import type { TProduct } from "@formbricks/types/product";
|
||||
import type { TEnvironment } from "@formbricks/types/environment";
|
||||
import { SearchBox } from "@formbricks/ui/SearchBox";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
|
||||
type TemplateContainerWithPreviewProps = {
|
||||
environmentId: string;
|
||||
product: TProduct;
|
||||
environment: TEnvironment;
|
||||
profile: TProfile;
|
||||
};
|
||||
|
||||
export default function TemplateContainerWithPreview({
|
||||
environmentId,
|
||||
product,
|
||||
environment,
|
||||
profile,
|
||||
}: TemplateContainerWithPreviewProps) {
|
||||
const [activeTemplate, setActiveTemplate] = useState<TTemplate | null>(null);
|
||||
const [activeQuestionId, setActiveQuestionId] = useState<string | null>(null);
|
||||
@@ -56,6 +59,7 @@ export default function TemplateContainerWithPreview({
|
||||
environmentId={environmentId}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={profile}
|
||||
templateSearch={templateSearch ?? ""}
|
||||
onTemplateClick={(template) => {
|
||||
setActiveQuestionId(template.preset.questions[0].id);
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import LoadingSpinner from "@formbricks/ui/LoadingSpinner";
|
||||
import { useProfile } from "@/app/lib/profile";
|
||||
import { replacePresetPlaceholders } from "@/app/lib/templates";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import type { TEnvironment } from "@formbricks/types/environment";
|
||||
import type { TProduct } from "@formbricks/types/product";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TSurveyInput } from "@formbricks/types/surveys";
|
||||
import { TTemplate } from "@formbricks/types/templates";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui/Tooltip";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { ErrorComponent } from "@formbricks/ui/ErrorComponent";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui/Tooltip";
|
||||
import { PlusCircleIcon } from "@heroicons/react/24/outline";
|
||||
import { SparklesIcon } from "@heroicons/react/24/solid";
|
||||
import { SplitIcon } from "lucide-react";
|
||||
@@ -17,10 +16,10 @@ import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { createSurveyAction } from "../actions";
|
||||
import { customSurvey, templates } from "./templates";
|
||||
import { TSurveyInput } from "@formbricks/types/surveys";
|
||||
|
||||
type TemplateList = {
|
||||
environmentId: string;
|
||||
profile: TProfile;
|
||||
onTemplateClick: (template: TTemplate) => void;
|
||||
environment: TEnvironment;
|
||||
product: TProduct;
|
||||
@@ -31,6 +30,7 @@ const ALL_CATEGORY_NAME = "All";
|
||||
const RECOMMENDED_CATEGORY_NAME = "For you";
|
||||
export default function TemplateList({
|
||||
environmentId,
|
||||
profile,
|
||||
onTemplateClick,
|
||||
product,
|
||||
environment,
|
||||
@@ -40,7 +40,6 @@ export default function TemplateList({
|
||||
const [activeTemplate, setActiveTemplate] = useState<TTemplate | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [selectedFilter, setSelectedFilter] = useState(RECOMMENDED_CATEGORY_NAME);
|
||||
const { profile, isLoadingProfile, isErrorProfile } = useProfile();
|
||||
|
||||
const [categories, setCategories] = useState<Array<string>>([]);
|
||||
|
||||
@@ -78,14 +77,13 @@ export default function TemplateList({
|
||||
router.push(`/environments/${environmentId}/surveys/${survey.id}/edit`);
|
||||
};
|
||||
|
||||
if (isLoadingProfile) return <LoadingSpinner />;
|
||||
if (isErrorProfile) return <ErrorComponent />;
|
||||
|
||||
const filteredTemplates = templates.filter((template) => {
|
||||
const matchesCategory =
|
||||
selectedFilter === ALL_CATEGORY_NAME ||
|
||||
template.category === selectedFilter ||
|
||||
(selectedFilter === RECOMMENDED_CATEGORY_NAME && template.objectives?.includes(profile.objective));
|
||||
(profile.objective &&
|
||||
selectedFilter === RECOMMENDED_CATEGORY_NAME &&
|
||||
template.objectives?.includes(profile.objective));
|
||||
|
||||
const templateName = template.name?.toLowerCase();
|
||||
const templateDescription = template.description?.toLowerCase();
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import TemplateContainerWithPreview from "./TemplateContainer";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
import TemplateContainerWithPreview from "./TemplateContainer";
|
||||
|
||||
export default async function SurveyTemplatesPage({ params }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
const environmentId = params.environmentId;
|
||||
const environment = await getEnvironment(environmentId);
|
||||
const product = await getProductByEnvironmentId(environmentId);
|
||||
|
||||
const [environment, product] = await Promise.all([
|
||||
getEnvironment(environmentId),
|
||||
getProductByEnvironmentId(environmentId),
|
||||
]);
|
||||
|
||||
if (!session) {
|
||||
throw new Error("Session not found");
|
||||
}
|
||||
|
||||
if (!product) {
|
||||
throw new Error("Product not found");
|
||||
@@ -16,6 +26,11 @@ export default async function SurveyTemplatesPage({ params }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<TemplateContainerWithPreview environmentId={environmentId} environment={environment} product={product} />
|
||||
<TemplateContainerWithPreview
|
||||
environmentId={environmentId}
|
||||
profile={session.user}
|
||||
environment={environment}
|
||||
product={product}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
export const updateMemberRole = async (teamId: string, userId: string, role: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/members/${userId}/`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ role }),
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const transferOwnership = async (teamId: string, userId: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/transfer-ownership/`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ userId }),
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const removeMember = async (teamId: string, userId: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/members/${userId}/`, {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// update invitee's role
|
||||
export const updateInviteeRole = async (teamId: string, inviteId: string, role: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/invite/${inviteId}/`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ role }),
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteInvite = async (teamId: string, inviteId: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/invite/${inviteId}/`, {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const addMember = async (teamId: string, data: { name: string; email: string }) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/invite/`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return result.status === 201;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const resendInvite = async (teamId: string, inviteId: string) => {
|
||||
try {
|
||||
const result = await fetch(`/api/v1/teams/${teamId}/invite/${inviteId}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return result.status === 200;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const shareInvite = async (teamId: string, inviteId: string) => {
|
||||
try {
|
||||
const res = await fetch(`/api/v1/teams/${teamId}/invite/${inviteId}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
const json = await res.json();
|
||||
throw Error(json.message);
|
||||
}
|
||||
return res.json();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw Error(`shareInvite: unable to get invite link: ${error.message}`);
|
||||
}
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
import useSWR from "swr";
|
||||
import { fetcher } from "@formbricks/lib/fetcher";
|
||||
|
||||
export const useProfile = () => {
|
||||
const { data, isLoading, error, mutate, isValidating } = useSWR(`/api/v1/users/me/`, fetcher);
|
||||
|
||||
return {
|
||||
profile: data,
|
||||
isLoadingProfile: isLoading,
|
||||
isErrorProfile: error,
|
||||
isValidatingProfile: isValidating,
|
||||
mutateProfile: mutate,
|
||||
};
|
||||
};
|
||||
|
||||
export const updateProfile = async (profile) => {
|
||||
try {
|
||||
await fetch(`/api/v1/users/me/`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(profile),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
export const addResponseNote = async (
|
||||
environmentId: string,
|
||||
surveyId: string,
|
||||
responseId: string,
|
||||
text: string
|
||||
) => {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/v1/environments/${environmentId}/surveys/${surveyId}/responses/${responseId}/responsesNotes`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(text),
|
||||
}
|
||||
);
|
||||
return await res.json();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw Error(`createResponseNote: unable to create responseNote: ${error.message}`);
|
||||
}
|
||||
};
|
||||
@@ -27,13 +27,6 @@ export const truncateMiddle = (str: string, length: number) => {
|
||||
return str;
|
||||
};
|
||||
|
||||
export const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
export function isLight(color) {
|
||||
let r, g, b;
|
||||
if (color.length === 4) {
|
||||
@@ -48,33 +41,6 @@ export function isLight(color) {
|
||||
return r * 0.299 + g * 0.587 + b * 0.114 > 128;
|
||||
}
|
||||
|
||||
const shuffle = (array: any[]) => {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
};
|
||||
|
||||
export const shuffleArray = (array: any[], shuffleOption: string | undefined) => {
|
||||
const arrayCopy = [...array];
|
||||
const otherIndex = arrayCopy.findIndex((element) => element.id === "other");
|
||||
const otherElement = otherIndex !== -1 ? arrayCopy.splice(otherIndex, 1)[0] : null;
|
||||
|
||||
if (shuffleOption === "all") {
|
||||
shuffle(arrayCopy);
|
||||
} else if (shuffleOption === "exceptLast") {
|
||||
const lastElement = arrayCopy.pop();
|
||||
shuffle(arrayCopy);
|
||||
arrayCopy.push(lastElement);
|
||||
}
|
||||
|
||||
if (otherElement) {
|
||||
arrayCopy.push(otherElement);
|
||||
}
|
||||
|
||||
return arrayCopy;
|
||||
};
|
||||
|
||||
export enum MEMBERSHIP_ROLES {
|
||||
OWNER = "owner",
|
||||
ADMIN = "admin",
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
"react-hook-form": "^7.47.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-icons": "^4.11.0",
|
||||
"swr": "^2.2.4",
|
||||
"ua-parser-js": "^1.0.36",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
|
||||
@@ -26,6 +26,7 @@ const responseSelection = {
|
||||
onboardingCompleted: true,
|
||||
twoFactorEnabled: true,
|
||||
identityProvider: true,
|
||||
objective: true,
|
||||
};
|
||||
|
||||
export const getProfileCacheTag = (userId: string): string => `profiles-${userId}`;
|
||||
|
||||
@@ -22,6 +22,7 @@ export const ZProfile = z.object({
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
onboardingCompleted: z.boolean(),
|
||||
objective: ZProfileObjective.nullable(),
|
||||
});
|
||||
|
||||
export type TProfile = z.infer<typeof ZProfile>;
|
||||
@@ -31,7 +32,7 @@ export const ZProfileUpdateInput = z.object({
|
||||
email: z.string().optional(),
|
||||
onboardingCompleted: z.boolean().optional(),
|
||||
role: ZRole.optional(),
|
||||
objective: ZProfileObjective.optional(),
|
||||
objective: ZProfileObjective.nullish(),
|
||||
});
|
||||
|
||||
export type TProfileUpdateInput = z.infer<typeof ZProfileUpdateInput>;
|
||||
@@ -41,7 +42,7 @@ export const ZProfileCreateInput = z.object({
|
||||
email: z.string(),
|
||||
onboardingCompleted: z.boolean().optional(),
|
||||
role: ZRole.optional(),
|
||||
objective: ZProfileObjective.optional(),
|
||||
objective: ZProfileObjective.nullish(),
|
||||
});
|
||||
|
||||
export type TProfileCreateInput = z.infer<typeof ZProfileCreateInput>;
|
||||
|
||||
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
@@ -398,9 +398,6 @@ importers:
|
||||
react-icons:
|
||||
specifier: ^4.11.0
|
||||
version: 4.11.0(react@18.2.0)
|
||||
swr:
|
||||
specifier: ^2.2.4
|
||||
version: 2.2.4(react@18.2.0)
|
||||
ua-parser-js:
|
||||
specifier: ^1.0.36
|
||||
version: 1.0.36
|
||||
@@ -21461,16 +21458,6 @@ packages:
|
||||
es6-symbol: 3.1.3
|
||||
dev: true
|
||||
|
||||
/swr@2.2.4(react@18.2.0):
|
||||
resolution: {integrity: sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 18.2.0
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/symbol-tree@3.2.4:
|
||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||
dev: true
|
||||
|
||||
Reference in New Issue
Block a user