mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 10:19:51 -06:00
chore: renamed profile to user (#1770)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
81234c4bde
commit
663fa0124f
@@ -29,7 +29,7 @@ export default async function ResponseSection({
|
||||
<>
|
||||
{responses && (
|
||||
<ResponseTimeline
|
||||
profile={session.user}
|
||||
user={session.user}
|
||||
surveys={surveys}
|
||||
responses={responses}
|
||||
environment={environment}
|
||||
|
||||
@@ -7,17 +7,17 @@ import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { ArrowsUpDownIcon } from "@heroicons/react/24/outline";
|
||||
import { useState, useEffect } from "react";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
export default function ResponseTimeline({
|
||||
surveys,
|
||||
profile,
|
||||
user,
|
||||
environment,
|
||||
responses,
|
||||
environmentTags,
|
||||
}: {
|
||||
surveys: TSurvey[];
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
responses: TResponse[];
|
||||
environment: TEnvironment;
|
||||
environmentTags: TTag[];
|
||||
@@ -48,7 +48,7 @@ export default function ResponseTimeline({
|
||||
responses={sortedResponses}
|
||||
environment={environment}
|
||||
surveys={surveys}
|
||||
profile={profile}
|
||||
user={user}
|
||||
environmentTags={environmentTags}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
@@ -10,13 +10,13 @@ export default async function ResponseFeed({
|
||||
responses,
|
||||
environment,
|
||||
surveys,
|
||||
profile,
|
||||
user,
|
||||
environmentTags,
|
||||
}: {
|
||||
responses: TResponse[];
|
||||
environment: TEnvironment;
|
||||
surveys: TSurvey[];
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
environmentTags: TTag[];
|
||||
}) {
|
||||
return (
|
||||
@@ -34,7 +34,7 @@ export default async function ResponseFeed({
|
||||
<SingleResponseCard
|
||||
response={response}
|
||||
survey={survey}
|
||||
profile={profile}
|
||||
user={user}
|
||||
pageType="people"
|
||||
environmentTags={environmentTags}
|
||||
environment={environment}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { AuthorizationError } from "@formbricks/types/errors";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
|
||||
export async function updateNotificationSettingsAction(notificationSettings: TUserNotificationSettings) {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Switch } from "@formbricks/ui/Switch";
|
||||
import { useRouter } from "next/navigation";
|
||||
import toast from "react-hot-toast";
|
||||
import { updateNotificationSettingsAction } from "../actions";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
import { useState } from "react";
|
||||
|
||||
interface NotificationSwitchProps {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import SettingsCard from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
import { getServerSession } from "next-auth";
|
||||
import SettingsTitle from "../components/SettingsTitle";
|
||||
import EditAlerts from "./components/EditAlerts";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
|
||||
export interface Membership {
|
||||
team: {
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
import { disableTwoFactorAuth, enableTwoFactorAuth, setupTwoFactorAuth } from "@formbricks/lib/auth/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { updateProfile, deleteProfile } from "@formbricks/lib/profile/service";
|
||||
import { TProfileUpdateInput } from "@formbricks/types/profile";
|
||||
import { updateUser, deleteUser } from "@formbricks/lib/user/service";
|
||||
import { TUserUpdateInput } from "@formbricks/types/user";
|
||||
import { AuthorizationError } from "@formbricks/types/errors";
|
||||
|
||||
export async function updateProfileAction(data: Partial<TProfileUpdateInput>) {
|
||||
export async function updateUserAction(data: Partial<TUserUpdateInput>) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await updateProfile(session.user.id, data);
|
||||
return await updateUser(session.user.id, data);
|
||||
}
|
||||
|
||||
export async function deleteProfileAction() {
|
||||
export async function deleteUserAction() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await deleteProfile(session.user.id);
|
||||
return await deleteUser(session.user.id);
|
||||
}
|
||||
|
||||
export async function setupTwoFactorAuthAction(password: string) {
|
||||
@@ -79,5 +79,5 @@ export async function updateAvatarAction(avatarUrl: string) {
|
||||
throw new Error("User not found");
|
||||
}
|
||||
|
||||
return await updateProfile(session.user.id, { imageUrl: avatarUrl });
|
||||
return await updateUser(session.user.id, { imageUrl: avatarUrl });
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
import DisableTwoFactorModal from "@/app/(app)/environments/[environmentId]/settings/profile/components/DisableTwoFactorModal";
|
||||
import EnableTwoFactorModal from "@/app/(app)/environments/[environmentId]/settings/profile/components/EnableTwoFactorModal";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { Switch } from "@formbricks/ui/Switch";
|
||||
import React, { useState } from "react";
|
||||
|
||||
const AccountSecurity = ({ profile }: { profile: TProfile }) => {
|
||||
const AccountSecurity = ({ user }: { user: TUser }) => {
|
||||
const [twoFactorModalOpen, setTwoFactorModalOpen] = useState(false);
|
||||
const [disableTwoFactorModalOpen, setDisableTwoFactorModalOpen] = useState(false);
|
||||
|
||||
@@ -14,7 +14,7 @@ const AccountSecurity = ({ profile }: { profile: TProfile }) => {
|
||||
<div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<Switch
|
||||
checked={profile.twoFactorEnabled}
|
||||
checked={user.twoFactorEnabled}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
setTwoFactorModalOpen(true);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { signOut } from "next-auth/react";
|
||||
import Image from "next/image";
|
||||
import { Dispatch, SetStateAction, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { deleteProfileAction } from "../actions";
|
||||
import { deleteUserAction } from "../actions";
|
||||
|
||||
export function EditAvatar({ session }) {
|
||||
return (
|
||||
@@ -52,7 +52,7 @@ function DeleteAccountModal({ setOpen, open, session }: DeleteAccountModalProps)
|
||||
const deleteAccount = async () => {
|
||||
try {
|
||||
setDeleting(true);
|
||||
await deleteProfileAction();
|
||||
await deleteUserAction();
|
||||
await signOut();
|
||||
await formbricksLogout();
|
||||
} catch (error) {
|
||||
|
||||
@@ -5,14 +5,14 @@ import { Input } from "@formbricks/ui/Input";
|
||||
import { Label } from "@formbricks/ui/Label";
|
||||
import { useForm, SubmitHandler } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import { updateProfileAction } from "../actions";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { updateUserAction } from "../actions";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
type FormData = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export function EditName({ profile }: { profile: TProfile }) {
|
||||
export function EditName({ user }: { user: TUser }) {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
@@ -20,7 +20,7 @@ export function EditName({ profile }: { profile: TProfile }) {
|
||||
watch,
|
||||
} = useForm<FormData>();
|
||||
|
||||
const nameValue = watch("name", profile.name || "");
|
||||
const nameValue = watch("name", user.name || "");
|
||||
const isNotEmptySpaces = (value: string) => value.trim() !== "";
|
||||
|
||||
const onSubmit: SubmitHandler<FormData> = async (data) => {
|
||||
@@ -30,11 +30,11 @@ export function EditName({ profile }: { profile: TProfile }) {
|
||||
toast.error("Please enter at least one character");
|
||||
return;
|
||||
}
|
||||
if (data.name === profile.name) {
|
||||
if (data.name === user.name) {
|
||||
toast.success("This is already your name");
|
||||
return;
|
||||
}
|
||||
await updateProfileAction({ name: data.name });
|
||||
await updateUserAction({ name: data.name });
|
||||
toast.success("Your name was updated successfully");
|
||||
} catch (error) {
|
||||
toast.error(`Error: ${error.message}`);
|
||||
@@ -48,13 +48,13 @@ export function EditName({ profile }: { profile: TProfile }) {
|
||||
<Input
|
||||
type="text"
|
||||
id="fullname"
|
||||
defaultValue={profile.name || ""}
|
||||
defaultValue={user.name || ""}
|
||||
{...register("name", { required: true })}
|
||||
/>
|
||||
|
||||
<div className="mt-4">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input type="email" id="fullname" defaultValue={profile.email} disabled />
|
||||
<Input type="email" id="fullname" defaultValue={user.email} disabled />
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
|
||||
@@ -3,7 +3,7 @@ export const revalidate = REVALIDATION_INTERVAL;
|
||||
import AccountSecurity from "@/app/(app)/environments/[environmentId]/settings/profile/components/AccountSecurity";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
|
||||
import { getProfile } from "@formbricks/lib/profile/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { SettingsId } from "@formbricks/ui/SettingsId";
|
||||
import { getServerSession } from "next-auth";
|
||||
import SettingsCard from "../components/SettingsCard";
|
||||
@@ -15,22 +15,22 @@ import { EditName } from "./components/EditName";
|
||||
export default async function ProfileSettingsPage({ params }: { params: { environmentId: string } }) {
|
||||
const { environmentId } = params;
|
||||
const session = await getServerSession(authOptions);
|
||||
const profile = session && session.user ? await getProfile(session.user.id) : null;
|
||||
const user = session && session.user ? await getUser(session.user.id) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{profile && (
|
||||
{user && (
|
||||
<div>
|
||||
<SettingsTitle title="Profile" />
|
||||
<SettingsCard title="Personal Information" description="Update your personal information.">
|
||||
<EditName profile={profile} />
|
||||
<EditName user={user} />
|
||||
</SettingsCard>
|
||||
<SettingsCard title="Avatar" description="Assist your team in identifying you on Formbricks.">
|
||||
<EditAvatar session={session} environmentId={environmentId} />
|
||||
</SettingsCard>
|
||||
{profile.identityProvider === "email" && (
|
||||
{user.identityProvider === "email" && (
|
||||
<SettingsCard title="Security" description="Manage your password and other security settings.">
|
||||
<AccountSecurity profile={profile} />
|
||||
<AccountSecurity user={user} />
|
||||
</SettingsCard>
|
||||
)}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default async function ProfileSettingsPage({ params }: { params: { enviro
|
||||
description="Delete your account with all of your personal information and data.">
|
||||
<DeleteAccount session={session} />
|
||||
</SettingsCard>
|
||||
<SettingsId title="Profile" id={profile.id}></SettingsId>
|
||||
<SettingsId title="Profile" id={user.id}></SettingsId>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useEffect, useMemo } from "react";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TMembershipRole } from "@formbricks/types/memberships";
|
||||
|
||||
interface ResponsePageProps {
|
||||
@@ -23,7 +23,7 @@ interface ResponsePageProps {
|
||||
responses: TResponse[];
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
environmentTags: TTag[];
|
||||
responsesPerPage: number;
|
||||
membershipRole?: TMembershipRole;
|
||||
@@ -36,7 +36,7 @@ const ResponsePage = ({
|
||||
responses,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
environmentTags,
|
||||
responsesPerPage,
|
||||
membershipRole,
|
||||
@@ -63,7 +63,7 @@ const ResponsePage = ({
|
||||
surveyId={surveyId}
|
||||
webAppUrl={webAppUrl}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
membershipRole={membershipRole}
|
||||
/>
|
||||
<CustomFilter
|
||||
@@ -78,7 +78,7 @@ const ResponsePage = ({
|
||||
surveyId={surveyId}
|
||||
responses={filterResponses}
|
||||
survey={survey}
|
||||
profile={profile}
|
||||
user={user}
|
||||
environmentTags={environmentTags}
|
||||
responsesPerPage={responsesPerPage}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { useState, useEffect, useRef } from "react";
|
||||
import EmptyInAppSurveys from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/EmptyInAppSurveys";
|
||||
import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
@@ -14,7 +14,7 @@ interface ResponseTimelineProps {
|
||||
surveyId: string;
|
||||
responses: TResponse[];
|
||||
survey: TSurvey;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
environmentTags: TTag[];
|
||||
responsesPerPage: number;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export default function ResponseTimeline({
|
||||
environment,
|
||||
responses,
|
||||
survey,
|
||||
profile,
|
||||
user,
|
||||
environmentTags,
|
||||
responsesPerPage,
|
||||
}: ResponseTimelineProps) {
|
||||
@@ -76,7 +76,7 @@ export default function ResponseTimeline({
|
||||
<SingleResponseCard
|
||||
survey={survey}
|
||||
response={response}
|
||||
profile={profile}
|
||||
user={user}
|
||||
environmentTags={environmentTags}
|
||||
pageType="response"
|
||||
environment={environment}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { RESPONSES_PER_PAGE, REVALIDATION_INTERVAL, WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
|
||||
import { getProfile } from "@formbricks/lib/profile/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { getMembershipByUserIdTeamId } from "@formbricks/lib/membership/service";
|
||||
@@ -29,9 +29,9 @@ export default async function Page({ params }) {
|
||||
throw new Error("Product not found");
|
||||
}
|
||||
|
||||
const profile = await getProfile(session.user.id);
|
||||
if (!profile) {
|
||||
throw new Error("Profile not found");
|
||||
const user = await getUser(session.user.id);
|
||||
if (!user) {
|
||||
throw new Error("User not found");
|
||||
}
|
||||
const tags = await getTagsByEnvironmentId(params.environmentId);
|
||||
const team = await getTeamByEnvironmentId(params.environmentId);
|
||||
@@ -51,7 +51,7 @@ export default async function Page({ params }) {
|
||||
webAppUrl={WEBAPP_URL}
|
||||
product={product}
|
||||
environmentTags={tags}
|
||||
profile={profile}
|
||||
user={user}
|
||||
responsesPerPage={RESPONSES_PER_PAGE}
|
||||
membershipRole={currentUserMembership?.role}
|
||||
/>
|
||||
|
||||
@@ -7,14 +7,14 @@ import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import ShareEmbedSurvey from "./ShareEmbedSurvey";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
interface LinkSurveyShareButtonProps {
|
||||
survey: TSurvey;
|
||||
className?: string;
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
}
|
||||
|
||||
export default function LinkSurveyShareButton({
|
||||
@@ -22,7 +22,7 @@ export default function LinkSurveyShareButton({
|
||||
className,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
}: LinkSurveyShareButtonProps) {
|
||||
const [showLinkModal, setShowLinkModal] = useState(false);
|
||||
|
||||
@@ -46,7 +46,7 @@ export default function LinkSurveyShareButton({
|
||||
setOpen={setShowLinkModal}
|
||||
product={product}
|
||||
webAppUrl={webAppUrl}
|
||||
profile={profile}
|
||||
user={user}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import LinkSingleUseSurveyModal from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/LinkSingleUseSurveyModal";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Dialog, DialogContent } from "@formbricks/ui/Dialog";
|
||||
@@ -19,7 +19,7 @@ interface ShareEmbedSurveyProps {
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
}
|
||||
export default function ShareEmbedSurvey({
|
||||
survey,
|
||||
@@ -27,11 +27,11 @@ export default function ShareEmbedSurvey({
|
||||
setOpen,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
}: ShareEmbedSurveyProps) {
|
||||
const surveyUrl = useMemo(() => webAppUrl + "/s/" + survey.id, [survey]);
|
||||
const isSingleUseLinkSurvey = survey.singleUse?.enabled;
|
||||
const { email } = profile;
|
||||
const { email } = user;
|
||||
const { brandColor } = product;
|
||||
const surveyBrandColor = survey.productOverwrites?.brandColor || brandColor;
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ import toast from "react-hot-toast";
|
||||
import ShareEmbedSurvey from "./ShareEmbedSurvey";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
interface SummaryMetadataProps {
|
||||
environment: TEnvironment;
|
||||
survey: TSurvey;
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
singleUseIds?: string[];
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function SuccessMessage({
|
||||
survey,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
}: SummaryMetadataProps) {
|
||||
const searchParams = useSearchParams();
|
||||
const [showLinkModal, setShowLinkModal] = useState(false);
|
||||
@@ -62,7 +62,7 @@ export default function SuccessMessage({
|
||||
setOpen={setShowLinkModal}
|
||||
webAppUrl={webAppUrl}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
/>
|
||||
{confetti && <Confetti />}
|
||||
</>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import SummaryDropOffs from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryDropOffs";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
@@ -26,7 +26,7 @@ interface SummaryPageProps {
|
||||
responses: TResponse[];
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
environmentTags: TTag[];
|
||||
displayCount: number;
|
||||
responsesPerPage: number;
|
||||
@@ -40,7 +40,7 @@ const SummaryPage = ({
|
||||
responses,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
environmentTags,
|
||||
displayCount,
|
||||
responsesPerPage,
|
||||
@@ -69,7 +69,7 @@ const SummaryPage = ({
|
||||
surveyId={surveyId}
|
||||
webAppUrl={webAppUrl}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
membershipRole={membershipRole}
|
||||
/>
|
||||
<CustomFilter
|
||||
|
||||
@@ -7,7 +7,7 @@ import { REVALIDATION_INTERVAL, TEXT_RESPONSES_PER_PAGE, WEBAPP_URL } from "@for
|
||||
import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getMembershipByUserIdTeamId } from "@formbricks/lib/membership/service";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
|
||||
import { getProfile } from "@formbricks/lib/profile/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
@@ -31,9 +31,9 @@ export default async function Page({ params }) {
|
||||
throw new Error("Product not found");
|
||||
}
|
||||
|
||||
const profile = await getProfile(session.user.id);
|
||||
if (!profile) {
|
||||
throw new Error("Profile not found");
|
||||
const user = await getUser(session.user.id);
|
||||
if (!user) {
|
||||
throw new Error("User not found");
|
||||
}
|
||||
|
||||
const team = await getTeamByEnvironmentId(params.environmentId);
|
||||
@@ -55,7 +55,7 @@ export default async function Page({ params }) {
|
||||
surveyId={params.surveyId}
|
||||
webAppUrl={WEBAPP_URL}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
environmentTags={tags}
|
||||
displayCount={displayCount}
|
||||
responsesPerPage={TEXT_RESPONSES_PER_PAGE}
|
||||
|
||||
@@ -23,7 +23,7 @@ import LinkSurveyShareButton from "@/app/(app)/environments/[environmentId]/surv
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { updateSurveyAction } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/actions";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import SurveyStatusDropdown from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown";
|
||||
import { TMembershipRole } from "@formbricks/types/memberships";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
@@ -34,7 +34,7 @@ interface SummaryHeaderProps {
|
||||
survey: TSurvey;
|
||||
webAppUrl: string;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
membershipRole?: TMembershipRole;
|
||||
}
|
||||
const SummaryHeader = ({
|
||||
@@ -43,7 +43,7 @@ const SummaryHeader = ({
|
||||
survey,
|
||||
webAppUrl,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
membershipRole,
|
||||
}: SummaryHeaderProps) => {
|
||||
const router = useRouter();
|
||||
@@ -60,7 +60,7 @@ const SummaryHeader = ({
|
||||
</div>
|
||||
<div className="hidden justify-end gap-x-1.5 sm:flex">
|
||||
{survey.type === "link" && (
|
||||
<LinkSurveyShareButton survey={survey} webAppUrl={webAppUrl} product={product} profile={profile} />
|
||||
<LinkSurveyShareButton survey={survey} webAppUrl={webAppUrl} product={product} user={user} />
|
||||
)}
|
||||
{!isViewer &&
|
||||
(environment?.widgetSetupCompleted || survey.type === "link") &&
|
||||
@@ -92,7 +92,7 @@ const SummaryHeader = ({
|
||||
survey={survey}
|
||||
webAppUrl={webAppUrl}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
@@ -177,7 +177,7 @@ const SummaryHeader = ({
|
||||
survey={survey}
|
||||
webAppUrl={webAppUrl}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -53,7 +53,7 @@ export default async function SurveysList({ environmentId }: { environmentId: st
|
||||
environmentId={environmentId}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={session.user}
|
||||
user={session.user}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,18 +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";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
export default function SurveyStarter({
|
||||
environmentId,
|
||||
environment,
|
||||
product,
|
||||
profile,
|
||||
user,
|
||||
}: {
|
||||
environmentId: string;
|
||||
environment: TEnvironment;
|
||||
product: TProduct;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
}) {
|
||||
const [isCreateSurveyLoading, setIsCreateSurveyLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
@@ -59,7 +59,7 @@ export default function SurveyStarter({
|
||||
}}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -10,20 +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";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
type TemplateContainerWithPreviewProps = {
|
||||
environmentId: string;
|
||||
product: TProduct;
|
||||
environment: TEnvironment;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
};
|
||||
|
||||
export default function TemplateContainerWithPreview({
|
||||
environmentId,
|
||||
product,
|
||||
environment,
|
||||
profile,
|
||||
user,
|
||||
}: TemplateContainerWithPreviewProps) {
|
||||
const [activeTemplate, setActiveTemplate] = useState<TTemplate | null>(null);
|
||||
const [activeQuestionId, setActiveQuestionId] = useState<string | null>(null);
|
||||
@@ -59,7 +59,7 @@ export default function TemplateContainerWithPreview({
|
||||
environmentId={environmentId}
|
||||
environment={environment}
|
||||
product={product}
|
||||
profile={profile}
|
||||
user={user}
|
||||
templateSearch={templateSearch ?? ""}
|
||||
onTemplateClick={(template) => {
|
||||
setActiveQuestionId(template.preset.questions[0].id);
|
||||
|
||||
@@ -4,7 +4,7 @@ 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 { TUser } from "@formbricks/types/user";
|
||||
import { TSurveyInput } from "@formbricks/types/surveys";
|
||||
import { TTemplate } from "@formbricks/types/templates";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
@@ -19,7 +19,7 @@ import { customSurvey, templates, testTemplate } from "./templates";
|
||||
|
||||
type TemplateList = {
|
||||
environmentId: string;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
onTemplateClick: (template: TTemplate) => void;
|
||||
environment: TEnvironment;
|
||||
product: TProduct;
|
||||
@@ -30,7 +30,7 @@ const ALL_CATEGORY_NAME = "All";
|
||||
const RECOMMENDED_CATEGORY_NAME = "For you";
|
||||
export default function TemplateList({
|
||||
environmentId,
|
||||
profile,
|
||||
user,
|
||||
onTemplateClick,
|
||||
product,
|
||||
environment,
|
||||
@@ -50,7 +50,7 @@ export default function TemplateList({
|
||||
];
|
||||
|
||||
const fullCategories =
|
||||
!!profile?.objective && profile.objective !== "other"
|
||||
!!user?.objective && user.objective !== "other"
|
||||
? [RECOMMENDED_CATEGORY_NAME, ALL_CATEGORY_NAME, ...defaultCategories]
|
||||
: [ALL_CATEGORY_NAME, ...defaultCategories];
|
||||
|
||||
@@ -58,11 +58,11 @@ export default function TemplateList({
|
||||
|
||||
const activeFilter = templateSearch
|
||||
? ALL_CATEGORY_NAME
|
||||
: !!profile?.objective && profile.objective !== "other"
|
||||
: !!user?.objective && user.objective !== "other"
|
||||
? RECOMMENDED_CATEGORY_NAME
|
||||
: ALL_CATEGORY_NAME;
|
||||
setSelectedFilter(activeFilter);
|
||||
}, [profile, templateSearch]);
|
||||
}, [user, templateSearch]);
|
||||
|
||||
const addSurvey = async (activeTemplate) => {
|
||||
setLoading(true);
|
||||
@@ -81,9 +81,9 @@ export default function TemplateList({
|
||||
const matchesCategory =
|
||||
selectedFilter === ALL_CATEGORY_NAME ||
|
||||
template.category === selectedFilter ||
|
||||
(profile.objective &&
|
||||
(user.objective &&
|
||||
selectedFilter === RECOMMENDED_CATEGORY_NAME &&
|
||||
template.objectives?.includes(profile.objective));
|
||||
template.objectives?.includes(user.objective));
|
||||
|
||||
const templateName = template.name?.toLowerCase();
|
||||
const templateDescription = template.description?.toLowerCase();
|
||||
|
||||
@@ -28,7 +28,7 @@ export default async function SurveyTemplatesPage({ params }) {
|
||||
return (
|
||||
<TemplateContainerWithPreview
|
||||
environmentId={environmentId}
|
||||
profile={session.user}
|
||||
user={session.user}
|
||||
environment={environment}
|
||||
product={product}
|
||||
/>
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { canUserAccessProduct, verifyUserRoleAccess } from "@formbricks/lib/product/auth";
|
||||
import { getProduct, updateProduct } from "@formbricks/lib/product/service";
|
||||
import { updateProfile } from "@formbricks/lib/profile/service";
|
||||
import { updateUser } from "@formbricks/lib/user/service";
|
||||
import { AuthorizationError } from "@formbricks/types/errors";
|
||||
import { TProductUpdateInput } from "@formbricks/types/product";
|
||||
import { TProfileUpdateInput } from "@formbricks/types/profile";
|
||||
import { TUserUpdateInput } from "@formbricks/types/user";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
export async function updateProfileAction(updatedProfile: TProfileUpdateInput) {
|
||||
export async function updateUserAction(updatedUser: TUserUpdateInput) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await updateProfile(session.user.id, updatedProfile);
|
||||
return await updateUser(session.user.id, updatedUser);
|
||||
}
|
||||
|
||||
export async function updateProductAction(productId: string, updatedProduct: Partial<TProductUpdateInput>) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { updateProfileAction } from "@/app/(app)/onboarding/actions";
|
||||
import { updateUserAction } from "@/app/(app)/onboarding/actions";
|
||||
import { formbricksEnabled, updateResponse } from "@/app/lib/formbricks";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { env } from "@formbricks/lib/env.mjs";
|
||||
import { TProfile, TProfileObjective } from "@formbricks/types/profile";
|
||||
import { TUser, TUserObjective } from "@formbricks/types/user";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
@@ -14,15 +14,15 @@ type ObjectiveProps = {
|
||||
next: () => void;
|
||||
skip: () => void;
|
||||
formbricksResponseId?: string;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
};
|
||||
|
||||
type ObjectiveChoice = {
|
||||
label: string;
|
||||
id: TProfileObjective;
|
||||
id: TUserObjective;
|
||||
};
|
||||
|
||||
const Objective: React.FC<ObjectiveProps> = ({ next, skip, formbricksResponseId, profile }) => {
|
||||
const Objective: React.FC<ObjectiveProps> = ({ next, skip, formbricksResponseId, user }) => {
|
||||
const objectives: Array<ObjectiveChoice> = [
|
||||
{ label: "Increase conversion", id: "increase_conversion" },
|
||||
{ label: "Improve user retention", id: "improve_user_retention" },
|
||||
@@ -51,9 +51,9 @@ const Objective: React.FC<ObjectiveProps> = ({ next, skip, formbricksResponseId,
|
||||
if (selectedObjective) {
|
||||
try {
|
||||
setIsProfileUpdating(true);
|
||||
await updateProfileAction({
|
||||
await updateUserAction({
|
||||
objective: selectedObjective.id,
|
||||
name: profile.name ?? undefined,
|
||||
name: user.name ?? undefined,
|
||||
});
|
||||
setIsProfileUpdating(false);
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { updateProfileAction } from "@/app/(app)/onboarding/actions";
|
||||
import { updateUserAction } from "@/app/(app)/onboarding/actions";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { Logo } from "@formbricks/ui/Logo";
|
||||
import { ProgressBar } from "@formbricks/ui/ProgressBar";
|
||||
import { Session } from "next-auth";
|
||||
@@ -19,11 +19,11 @@ const MAX_STEPS = 6;
|
||||
interface OnboardingProps {
|
||||
session: Session;
|
||||
environmentId: string;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
product: TProduct;
|
||||
}
|
||||
|
||||
export default function Onboarding({ session, environmentId, profile, product }: OnboardingProps) {
|
||||
export default function Onboarding({ session, environmentId, user, product }: OnboardingProps) {
|
||||
const [formbricksResponseId, setFormbricksResponseId] = useState<string | undefined>();
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -53,8 +53,8 @@ export default function Onboarding({ session, environmentId, profile, product }:
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const updatedProfile = { ...profile, onboardingCompleted: true };
|
||||
await updateProfileAction(updatedProfile);
|
||||
const updatedProfile = { ...user, onboardingCompleted: true };
|
||||
await updateUserAction(updatedProfile);
|
||||
|
||||
if (environmentId) {
|
||||
router.push(`/environments/${environmentId}/surveys`);
|
||||
@@ -85,7 +85,7 @@ export default function Onboarding({ session, environmentId, profile, product }:
|
||||
</div>
|
||||
<div className="flex grow items-center justify-center">
|
||||
{currentStep === 1 && (
|
||||
<Greeting next={next} skip={doLater} name={profile.name ? profile.name : ""} session={session} />
|
||||
<Greeting next={next} skip={doLater} name={user.name ? user.name : ""} session={session} />
|
||||
)}
|
||||
{currentStep === 2 && (
|
||||
<Role
|
||||
@@ -96,12 +96,7 @@ export default function Onboarding({ session, environmentId, profile, product }:
|
||||
/>
|
||||
)}
|
||||
{currentStep === 3 && (
|
||||
<Objective
|
||||
next={next}
|
||||
skip={skipStep}
|
||||
formbricksResponseId={formbricksResponseId}
|
||||
profile={profile}
|
||||
/>
|
||||
<Objective next={next} skip={skipStep} formbricksResponseId={formbricksResponseId} user={user} />
|
||||
)}
|
||||
{currentStep === 4 && (
|
||||
<Product done={done} environmentId={environmentId} isLoading={isLoading} product={product} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { updateProfileAction } from "@/app/(app)/onboarding/actions";
|
||||
import { updateUserAction } from "@/app/(app)/onboarding/actions";
|
||||
import { createResponse, formbricksEnabled } from "@/app/lib/formbricks";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { env } from "@formbricks/lib/env.mjs";
|
||||
@@ -49,7 +49,7 @@ const Role: React.FC<RoleProps> = ({ next, skip, setFormbricksResponseId, sessio
|
||||
if (selectedRole) {
|
||||
try {
|
||||
setIsUpdating(true);
|
||||
await updateProfileAction({ role: selectedRole.id });
|
||||
await updateUserAction({ role: selectedRole.id });
|
||||
setIsUpdating(false);
|
||||
} catch (e) {
|
||||
setIsUpdating(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
|
||||
import { getFirstEnvironmentByUserId } from "@formbricks/lib/environment/service";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
|
||||
import { getProfile } from "@formbricks/lib/profile/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { getServerSession } from "next-auth";
|
||||
import Onboarding from "./components/Onboarding";
|
||||
import { redirect } from "next/navigation";
|
||||
@@ -21,12 +21,12 @@ export default async function OnboardingPage() {
|
||||
throw new Error("No environment found for user");
|
||||
}
|
||||
|
||||
const profile = await getProfile(userId);
|
||||
const user = await getUser(userId);
|
||||
const product = await getProductByEnvironmentId(environment?.id!);
|
||||
|
||||
if (!environment || !profile || !product) {
|
||||
throw new Error("Failed to get environment, profile, or product");
|
||||
if (!environment || !user || !product) {
|
||||
throw new Error("Failed to get environment, user, or product");
|
||||
}
|
||||
|
||||
return <Onboarding session={session} environmentId={environment.id} profile={profile} product={product} />;
|
||||
return <Onboarding session={session} environmentId={environment.id} user={user} product={product} />;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TResponseData } from "@formbricks/types/responses";
|
||||
import { TSurveyQuestion, TSurveyStatus } from "@formbricks/types/surveys";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
|
||||
export interface Insights {
|
||||
totalCompletedResponses: number;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { prisma } from "@formbricks/database";
|
||||
import { INTERNAL_SECRET } from "@formbricks/lib/constants";
|
||||
import { convertDatesInObject } from "@formbricks/lib/time";
|
||||
import { TSurveyQuestion } from "@formbricks/types/surveys";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
import { ZPipelineInput } from "@formbricks/types/pipelines";
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { deleteInvite } from "@formbricks/lib/invite/service";
|
||||
import { verifyInviteToken } from "@formbricks/lib/jwt";
|
||||
import { createMembership } from "@formbricks/lib/membership/service";
|
||||
import { createProduct } from "@formbricks/lib/product/service";
|
||||
import { createProfile } from "@formbricks/lib/profile/service";
|
||||
import { createUser } from "@formbricks/lib/user/service";
|
||||
import { createTeam, getTeam } from "@formbricks/lib/team/service";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function POST(request: Request) {
|
||||
let invite;
|
||||
|
||||
// create the user
|
||||
user = await createProfile(user);
|
||||
user = await createUser(user);
|
||||
|
||||
// User is invited to team
|
||||
if (inviteToken) {
|
||||
|
||||
@@ -88,7 +88,7 @@ export const resetPassword = async (token: string, password: string): Promise<an
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteProfile = async (): Promise<any> => {
|
||||
export const deleteUser = async (): Promise<any> => {
|
||||
try {
|
||||
const res = await fetch("/api/v1/users/me/", {
|
||||
method: "DELETE",
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
TSurveyVerifyEmail,
|
||||
} from "@formbricks/types/surveys";
|
||||
import { TTeamBilling } from "@formbricks/types/teams";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/users";
|
||||
import { TUserNotificationSettings } from "@formbricks/types/user";
|
||||
|
||||
declare global {
|
||||
namespace PrismaJson {
|
||||
|
||||
@@ -24,4 +24,4 @@ export {
|
||||
} from "@formbricks/types/surveys";
|
||||
|
||||
export { ZTeamBilling } from "@formbricks/types/teams";
|
||||
export { ZUserNotificationSettings } from "@formbricks/types/users";
|
||||
export { ZUserNotificationSettings } from "@formbricks/types/user";
|
||||
|
||||
@@ -7,16 +7,16 @@ import {
|
||||
updateMembership,
|
||||
} from "@formbricks/lib/membership/service";
|
||||
import { updateInvite } from "@formbricks/lib/invite/service";
|
||||
import { TInviteUpdateInput } from "../../../types/invites";
|
||||
import { TMembershipUpdateInput } from "../../../types/memberships";
|
||||
import { TInviteUpdateInput } from "@formbricks/types/invites";
|
||||
import { TMembershipUpdateInput } from "@formbricks/types/memberships";
|
||||
import { hasTeamAccess, hasTeamAuthority, isOwner } from "@formbricks/lib/auth";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AuthenticationError, AuthorizationError, ValidationError } from "../../../types/errors";
|
||||
import { TProfile } from "../../../types/profile";
|
||||
import { AuthenticationError, AuthorizationError, ValidationError } from "@formbricks/types/errors";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
export const transferOwnershipAction = async (teamId: string, newOwnerId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
const user = session?.user as TProfile;
|
||||
const user = session?.user as TUser;
|
||||
if (!session) {
|
||||
throw new AuthenticationError("Not authenticated");
|
||||
}
|
||||
@@ -49,7 +49,7 @@ export const transferOwnershipAction = async (teamId: string, newOwnerId: string
|
||||
|
||||
export const updateInviteAction = async (inviteId: string, teamId: string, data: TInviteUpdateInput) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
const user = session?.user as TProfile;
|
||||
const user = session?.user as TUser;
|
||||
|
||||
if (!user) {
|
||||
throw new AuthenticationError("Not authenticated");
|
||||
@@ -74,7 +74,7 @@ export const updateMembershipAction = async (
|
||||
data: TMembershipUpdateInput
|
||||
) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
const user = session?.user as TProfile;
|
||||
const user = session?.user as TUser;
|
||||
|
||||
if (!user) {
|
||||
throw new AuthenticationError("Not authenticated");
|
||||
|
||||
@@ -5,7 +5,7 @@ import { prisma } from "@formbricks/database";
|
||||
import { symmetricDecrypt, symmetricEncrypt } from "../crypto";
|
||||
import { verifyPassword } from "../auth";
|
||||
import { totpAuthenticatorCheck } from "../totp";
|
||||
import { profileCache } from "../profile/cache";
|
||||
import { userCache } from "../user/cache";
|
||||
import { ENCRYPTION_KEY } from "../constants";
|
||||
|
||||
export const setupTwoFactorAuth = async (
|
||||
@@ -120,7 +120,7 @@ export const enableTwoFactorAuth = async (id: string, code: string) => {
|
||||
},
|
||||
});
|
||||
|
||||
profileCache.revalidate({
|
||||
userCache.revalidate({
|
||||
id,
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ export const disableTwoFactorAuth = async (id: string, params: TDisableTwoFactor
|
||||
},
|
||||
});
|
||||
|
||||
profileCache.revalidate({
|
||||
userCache.revalidate({
|
||||
id,
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { env } from "./env.mjs";
|
||||
import { verifyToken } from "./jwt";
|
||||
import { createMembership } from "./membership/service";
|
||||
import { createProduct } from "./product/service";
|
||||
import { createProfile, getProfileByEmail, updateProfile } from "./profile/service";
|
||||
import { createUser, getUserByEmail, updateUser } from "./user/service";
|
||||
import { createTeam, getTeam } from "./team/service";
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
@@ -110,7 +110,7 @@ export const authOptions: NextAuthOptions = {
|
||||
throw new Error("Email already verified");
|
||||
}
|
||||
|
||||
user = await updateProfile(user.id, { emailVerified: new Date() });
|
||||
user = await updateUser(user.id, { emailVerified: new Date() });
|
||||
|
||||
return user;
|
||||
},
|
||||
@@ -132,7 +132,7 @@ export const authOptions: NextAuthOptions = {
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token }) {
|
||||
const existingUser = await getProfileByEmail(token?.email!);
|
||||
const existingUser = await getUserByEmail(token?.email!);
|
||||
|
||||
if (!existingUser) {
|
||||
return token;
|
||||
@@ -191,10 +191,10 @@ export const authOptions: NextAuthOptions = {
|
||||
// check if user with this email already exist
|
||||
// if not found just update user with new email address
|
||||
// if found throw an error (TODO find better solution)
|
||||
const otherUserWithEmail = await getProfileByEmail(user.email);
|
||||
const otherUserWithEmail = await getUserByEmail(user.email);
|
||||
|
||||
if (!otherUserWithEmail) {
|
||||
await updateProfile(existingUserWithAccount.id, { email: user.email });
|
||||
await updateUser(existingUserWithAccount.id, { email: user.email });
|
||||
return true;
|
||||
}
|
||||
throw new Error(
|
||||
@@ -205,13 +205,13 @@ export const authOptions: NextAuthOptions = {
|
||||
// There is no existing account for this identity provider / account id
|
||||
// check if user account with this email already exists
|
||||
// if user already exists throw error and request password login
|
||||
const existingUserWithEmail = await getProfileByEmail(user.email);
|
||||
const existingUserWithEmail = await getUserByEmail(user.email);
|
||||
|
||||
if (existingUserWithEmail) {
|
||||
throw new Error("A user with this email exists already.");
|
||||
}
|
||||
|
||||
const userProfile = await createProfile({
|
||||
const userProfile = await createUser({
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
emailVerified: new Date(Date.now()),
|
||||
|
||||
@@ -6,12 +6,12 @@ import { authOptions } from "../../authOptions";
|
||||
import { getTeamByEnvironmentId } from "../../team/service";
|
||||
import { AuthenticationError } from "@formbricks/types/errors";
|
||||
import { getMembershipByUserIdTeamId } from "../service";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
export const getMembershipByUserIdTeamIdAction = async (environmentId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
const team = await getTeamByEnvironmentId(environmentId);
|
||||
const user = session?.user as TProfile;
|
||||
const user = session?.user as TUser;
|
||||
|
||||
if (!session) {
|
||||
throw new AuthenticationError("Not authenticated");
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
|
||||
export const formatProfileDateFields = (profile: TProfile): TProfile => {
|
||||
if (typeof profile.createdAt === "string") {
|
||||
profile.createdAt = new Date(profile.createdAt);
|
||||
}
|
||||
if (typeof profile.updatedAt === "string") {
|
||||
profile.updatedAt = new Date(profile.updatedAt);
|
||||
}
|
||||
if (typeof profile.emailVerified === "string") {
|
||||
profile.emailVerified = new Date(profile.emailVerified);
|
||||
}
|
||||
|
||||
return profile;
|
||||
};
|
||||
@@ -5,13 +5,13 @@ interface RevalidateProps {
|
||||
email?: string;
|
||||
}
|
||||
|
||||
export const profileCache = {
|
||||
export const userCache = {
|
||||
tag: {
|
||||
byId(id: string) {
|
||||
return `profiles-${id}`;
|
||||
return `users-${id}`;
|
||||
},
|
||||
byEmail(email: string) {
|
||||
return `profiles-${email}`;
|
||||
return `users-${email}`;
|
||||
},
|
||||
},
|
||||
revalidate({ id, email }: RevalidateProps): void {
|
||||
@@ -4,13 +4,7 @@ import { prisma } from "@formbricks/database";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { TMembership } from "@formbricks/types/memberships";
|
||||
import {
|
||||
TProfile,
|
||||
TProfileCreateInput,
|
||||
TProfileUpdateInput,
|
||||
ZProfile,
|
||||
ZProfileUpdateInput,
|
||||
} from "@formbricks/types/profile";
|
||||
import { TUser, TUserCreateInput, TUserUpdateInput, ZUser, ZUserUpdateInput } from "@formbricks/types/user";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { z } from "zod";
|
||||
@@ -19,9 +13,7 @@ import { updateMembership } from "../membership/service";
|
||||
import { deleteTeam } from "../team/service";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { profileCache } from "./cache";
|
||||
import { formatProfileDateFields } from "./util";
|
||||
|
||||
import { userCache } from "./cache";
|
||||
const responseSelection = {
|
||||
id: true,
|
||||
name: true,
|
||||
@@ -36,24 +28,24 @@ const responseSelection = {
|
||||
objective: true,
|
||||
};
|
||||
|
||||
// function to retrive basic information about a user's profile
|
||||
export const getProfile = async (id: string): Promise<TProfile | null> => {
|
||||
const profile = await unstable_cache(
|
||||
// function to retrive basic information about a user's user
|
||||
export const getUser = async (id: string): Promise<TUser | null> => {
|
||||
const user = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([id, ZId]);
|
||||
|
||||
try {
|
||||
const profile = await prisma.user.findUnique({
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
if (!profile) {
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
return profile;
|
||||
return user;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -62,35 +54,35 @@ export const getProfile = async (id: string): Promise<TProfile | null> => {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[`getProfile-${id}`],
|
||||
[`getUser-${id}`],
|
||||
{
|
||||
tags: [profileCache.tag.byId(id)],
|
||||
tags: [userCache.tag.byId(id)],
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return profile
|
||||
return user
|
||||
? {
|
||||
...profile,
|
||||
...formatDateFields(profile, ZProfile),
|
||||
...user,
|
||||
...formatDateFields(user, ZUser),
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
export const getProfileByEmail = async (email: string): Promise<TProfile | null> => {
|
||||
const profile = await unstable_cache(
|
||||
export const getUserByEmail = async (email: string): Promise<TUser | null> => {
|
||||
const user = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([email, z.string().email()]);
|
||||
|
||||
try {
|
||||
const profile = await prisma.user.findFirst({
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email,
|
||||
},
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
return profile;
|
||||
return user;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -99,17 +91,17 @@ export const getProfileByEmail = async (email: string): Promise<TProfile | null>
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[`getProfileByEmail-${email}`],
|
||||
[`getUserByEmail-${email}`],
|
||||
{
|
||||
tags: [profileCache.tag.byEmail(email)],
|
||||
tags: [userCache.tag.byEmail(email)],
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return profile
|
||||
return user
|
||||
? {
|
||||
...profile,
|
||||
...formatProfileDateFields(profile),
|
||||
...user,
|
||||
...formatDateFields(user, ZUser),
|
||||
}
|
||||
: null;
|
||||
};
|
||||
@@ -117,12 +109,12 @@ export const getProfileByEmail = async (email: string): Promise<TProfile | null>
|
||||
const getAdminMemberships = (memberships: TMembership[]): TMembership[] =>
|
||||
memberships.filter((membership) => membership.role === "admin");
|
||||
|
||||
// function to update a user's profile
|
||||
export const updateProfile = async (personId: string, data: TProfileUpdateInput): Promise<TProfile> => {
|
||||
validateInputs([personId, ZId], [data, ZProfileUpdateInput.partial()]);
|
||||
// function to update a user's user
|
||||
export const updateUser = async (personId: string, data: TUserUpdateInput): Promise<TUser> => {
|
||||
validateInputs([personId, ZId], [data, ZUserUpdateInput.partial()]);
|
||||
|
||||
try {
|
||||
const updatedProfile = await prisma.user.update({
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: {
|
||||
id: personId,
|
||||
},
|
||||
@@ -130,57 +122,57 @@ export const updateProfile = async (personId: string, data: TProfileUpdateInput)
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
profileCache.revalidate({
|
||||
email: updatedProfile.email,
|
||||
id: updatedProfile.id,
|
||||
userCache.revalidate({
|
||||
email: updatedUser.email,
|
||||
id: updatedUser.id,
|
||||
});
|
||||
|
||||
return updatedProfile;
|
||||
return updatedUser;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2016") {
|
||||
throw new ResourceNotFoundError("Profile", personId);
|
||||
throw new ResourceNotFoundError("User", personId);
|
||||
} else {
|
||||
throw error; // Re-throw any other errors
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteUser = async (id: string): Promise<TProfile> => {
|
||||
const deleteUserById = async (id: string): Promise<TUser> => {
|
||||
validateInputs([id, ZId]);
|
||||
|
||||
const profile = await prisma.user.delete({
|
||||
const user = await prisma.user.delete({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
profileCache.revalidate({
|
||||
email: profile.email,
|
||||
userCache.revalidate({
|
||||
email: user.email,
|
||||
id,
|
||||
});
|
||||
|
||||
return profile;
|
||||
return user;
|
||||
};
|
||||
|
||||
export const createProfile = async (data: TProfileCreateInput): Promise<TProfile> => {
|
||||
validateInputs([data, ZProfileUpdateInput]);
|
||||
export const createUser = async (data: TUserCreateInput): Promise<TUser> => {
|
||||
validateInputs([data, ZUserUpdateInput]);
|
||||
|
||||
const profile = await prisma.user.create({
|
||||
const user = await prisma.user.create({
|
||||
data: data,
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
profileCache.revalidate({
|
||||
email: profile.email,
|
||||
id: profile.id,
|
||||
userCache.revalidate({
|
||||
email: user.email,
|
||||
id: user.id,
|
||||
});
|
||||
|
||||
return profile;
|
||||
return user;
|
||||
};
|
||||
|
||||
// function to delete a user's profile including teams
|
||||
export const deleteProfile = async (id: string): Promise<TProfile> => {
|
||||
// function to delete a user's user including teams
|
||||
export const deleteUser = async (id: string): Promise<TUser> => {
|
||||
validateInputs([id, ZId]);
|
||||
|
||||
try {
|
||||
@@ -219,9 +211,9 @@ export const deleteProfile = async (id: string): Promise<TProfile> => {
|
||||
}
|
||||
}
|
||||
|
||||
const deletedProfile = await deleteUser(id);
|
||||
const deletedUser = await deleteUserById(id);
|
||||
|
||||
return deletedProfile;
|
||||
return deletedUser;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -1,8 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import { ZProfile } from "./profile";
|
||||
import { ZUser } from "./user";
|
||||
|
||||
const ZAuthSession = z.object({
|
||||
user: ZProfile,
|
||||
user: ZUser,
|
||||
});
|
||||
|
||||
const ZAuthenticationApiKey = z.object({
|
||||
|
||||
4
packages/types/next-auth.d.ts
vendored
4
packages/types/next-auth.d.ts
vendored
@@ -1,11 +1,11 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { TProfile } from "./profile";
|
||||
import { TUser } from "./user";
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||
*/
|
||||
interface Session {
|
||||
user: TProfile;
|
||||
user: TUser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { ZSurveyWelcomeCard, ZSurveyHiddenFields, ZSurveyQuestions, ZSurveyThankYouCard } from "./surveys";
|
||||
import { ZProfileObjective } from "./profile";
|
||||
import { ZUserObjective } from "./user";
|
||||
|
||||
export const ZTemplate = z.object({
|
||||
name: z.string(),
|
||||
@@ -9,7 +9,7 @@ export const ZTemplate = z.object({
|
||||
category: z
|
||||
.enum(["Product Experience", "Exploration", "Growth", "Increase Revenue", "Customer Success"])
|
||||
.optional(),
|
||||
objectives: z.array(ZProfileObjective).optional(),
|
||||
objectives: z.array(ZUserObjective).optional(),
|
||||
preset: z.object({
|
||||
name: z.string(),
|
||||
welcomeCard: ZSurveyWelcomeCard,
|
||||
|
||||
@@ -2,7 +2,7 @@ import z from "zod";
|
||||
|
||||
const ZRole = z.enum(["project_manager", "engineer", "founder", "marketing_specialist", "other"]);
|
||||
|
||||
export const ZProfileObjective = z.enum([
|
||||
export const ZUserObjective = z.enum([
|
||||
"increase_conversion",
|
||||
"improve_user_retention",
|
||||
"increase_user_adoption",
|
||||
@@ -11,9 +11,9 @@ export const ZProfileObjective = z.enum([
|
||||
"other",
|
||||
]);
|
||||
|
||||
export type TProfileObjective = z.infer<typeof ZProfileObjective>;
|
||||
export type TUserObjective = z.infer<typeof ZUserObjective>;
|
||||
|
||||
export const ZProfile = z.object({
|
||||
export const ZUser = z.object({
|
||||
id: z.string(),
|
||||
name: z.string().nullable(),
|
||||
email: z.string(),
|
||||
@@ -24,32 +24,39 @@ export const ZProfile = z.object({
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
onboardingCompleted: z.boolean(),
|
||||
objective: ZProfileObjective.nullable(),
|
||||
objective: ZUserObjective.nullable(),
|
||||
});
|
||||
|
||||
export type TProfile = z.infer<typeof ZProfile>;
|
||||
export type TUser = z.infer<typeof ZUser>;
|
||||
|
||||
export const ZProfileUpdateInput = z.object({
|
||||
export const ZUserUpdateInput = z.object({
|
||||
name: z.string().nullish(),
|
||||
email: z.string().optional(),
|
||||
emailVerified: z.date().nullish(),
|
||||
onboardingCompleted: z.boolean().optional(),
|
||||
role: ZRole.optional(),
|
||||
objective: ZProfileObjective.nullish(),
|
||||
objective: ZUserObjective.nullish(),
|
||||
imageUrl: z.string().url().nullish(),
|
||||
});
|
||||
|
||||
export type TProfileUpdateInput = z.infer<typeof ZProfileUpdateInput>;
|
||||
export type TUserUpdateInput = z.infer<typeof ZUserUpdateInput>;
|
||||
|
||||
export const ZProfileCreateInput = z.object({
|
||||
export const ZUserCreateInput = z.object({
|
||||
name: z.string().optional(),
|
||||
email: z.string(),
|
||||
emailVerified: z.date().optional(),
|
||||
onboardingCompleted: z.boolean().optional(),
|
||||
role: ZRole.optional(),
|
||||
objective: ZProfileObjective.nullish(),
|
||||
objective: ZUserObjective.nullish(),
|
||||
identityProvider: z.enum(["email", "google", "github", "azuread"]).optional(),
|
||||
identityProviderAccountId: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TProfileCreateInput = z.infer<typeof ZProfileCreateInput>;
|
||||
export type TUserCreateInput = z.infer<typeof ZUserCreateInput>;
|
||||
|
||||
export const ZUserNotificationSettings = z.object({
|
||||
alert: z.record(z.boolean()),
|
||||
weeklySummary: z.record(z.boolean()),
|
||||
});
|
||||
|
||||
export type TUserNotificationSettings = z.infer<typeof ZUserNotificationSettings>;
|
||||
@@ -1,8 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ZUserNotificationSettings = z.object({
|
||||
alert: z.record(z.boolean()),
|
||||
weeklySummary: z.record(z.boolean()),
|
||||
});
|
||||
|
||||
export type TUserNotificationSettings = z.infer<typeof ZUserNotificationSettings>;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { timeSince } from "@formbricks/lib/time";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TResponseNote } from "@formbricks/types/responses";
|
||||
import { CheckIcon, PencilIcon, PlusIcon } from "@heroicons/react/24/solid";
|
||||
import clsx from "clsx";
|
||||
@@ -15,14 +15,14 @@ import { Button } from "../../Button";
|
||||
import { resolveResponseNoteAction, updateResponseNoteAction, createResponseNoteAction } from "../actions";
|
||||
|
||||
interface ResponseNotesProps {
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
responseId: string;
|
||||
notes: TResponseNote[];
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export default function ResponseNotes({ profile, responseId, notes, isOpen, setIsOpen }: ResponseNotesProps) {
|
||||
export default function ResponseNotes({ user, responseId, notes, isOpen, setIsOpen }: ResponseNotesProps) {
|
||||
const router = useRouter();
|
||||
const [noteText, setNoteText] = useState("");
|
||||
const [isCreatingNote, setIsCreatingNote] = useState(false);
|
||||
@@ -35,7 +35,7 @@ export default function ResponseNotes({ profile, responseId, notes, isOpen, setI
|
||||
e.preventDefault();
|
||||
setIsCreatingNote(true);
|
||||
try {
|
||||
await createResponseNoteAction(responseId, profile.id, noteText);
|
||||
await createResponseNoteAction(responseId, user.id, noteText);
|
||||
router.refresh();
|
||||
setIsCreatingNote(false);
|
||||
setNoteText("");
|
||||
@@ -162,7 +162,7 @@ export default function ResponseNotes({ profile, responseId, notes, isOpen, setI
|
||||
</span>
|
||||
<div className="flex items-center">
|
||||
<span className="block text-slate-700">{note.text}</span>
|
||||
{profile.id === note.user.id && (
|
||||
{user.id === note.user.id && (
|
||||
<button
|
||||
className="ml-auto hidden group-hover/notetext:block"
|
||||
onClick={() => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { timeSince } from "@formbricks/lib/time";
|
||||
import { TSurveyQuestionType } from "@formbricks/types/surveys";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TProfile } from "@formbricks/types/profile";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
@@ -34,7 +34,7 @@ import { formatDateWithOrdinal } from "@formbricks/lib/utils/datetime";
|
||||
export interface SingleResponseCardProps {
|
||||
survey: TSurvey;
|
||||
response: TResponse;
|
||||
profile: TProfile;
|
||||
user: TUser;
|
||||
pageType: string;
|
||||
environmentTags: TTag[];
|
||||
environment: TEnvironment;
|
||||
@@ -72,7 +72,7 @@ function DateResponse({ date }: { date?: string }) {
|
||||
export default function SingleResponseCard({
|
||||
survey,
|
||||
response,
|
||||
profile,
|
||||
user,
|
||||
pageType,
|
||||
environmentTags,
|
||||
environment,
|
||||
@@ -393,7 +393,7 @@ export default function SingleResponseCard({
|
||||
</div>
|
||||
{pageType === "response" && (
|
||||
<ResponseNotes
|
||||
profile={profile}
|
||||
user={user}
|
||||
responseId={response.id}
|
||||
notes={response.notes}
|
||||
isOpen={isOpen}
|
||||
|
||||
Reference in New Issue
Block a user