chore: remove swr from dependencies (#1407)

This commit is contained in:
Matti Nannt
2023-10-22 18:55:59 +02:00
committed by GitHub
parent 27c1b0d3f2
commit 0cc8cdf52a
13 changed files with 55 additions and 225 deletions

View File

@@ -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 (

View File

@@ -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}
/>
</>
)}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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}
/>
);
}

View File

@@ -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}`);
}
};

View File

@@ -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);
}
};

View File

@@ -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}`);
}
};

View File

@@ -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",

View File

@@ -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"
},

View File

@@ -26,6 +26,7 @@ const responseSelection = {
onboardingCompleted: true,
twoFactorEnabled: true,
identityProvider: true,
objective: true,
};
export const getProfileCacheTag = (userId: string): string => `profiles-${userId}`;

View File

@@ -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
View File

@@ -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