chore: renamed profile to user (#1770)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Dhruwang Jariwala
2023-12-12 16:02:51 +05:30
committed by GitHub
parent 81234c4bde
commit 663fa0124f
51 changed files with 234 additions and 263 deletions

View File

@@ -29,7 +29,7 @@ export default async function ResponseSection({
<>
{responses && (
<ResponseTimeline
profile={session.user}
user={session.user}
surveys={surveys}
responses={responses}
environment={environment}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import { TUserNotificationSettings } from "@formbricks/types/users";
import { TUserNotificationSettings } from "@formbricks/types/user";
export interface Membership {
team: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -53,7 +53,7 @@ export default async function SurveysList({ environmentId }: { environmentId: st
environmentId={environmentId}
environment={environment}
product={product}
profile={session.user}
user={session.user}
/>
);
}

View File

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

View File

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

View File

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

View File

@@ -28,7 +28,7 @@ export default async function SurveyTemplatesPage({ params }) {
return (
<TemplateContainerWithPreview
environmentId={environmentId}
profile={session.user}
user={session.user}
environment={environment}
product={product}
/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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={() => {

View File

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