diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx index ad5795ab3d..759a3d4efa 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx @@ -6,11 +6,13 @@ import { ReferralSignatureSetting } from "@/app/(app)/[emailAccountId]/assistant import { LearnedPatternsSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/LearnedPatternsSetting"; import { PersonalSignatureSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/PersonalSignatureSetting"; import { MultiRuleSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/MultiRuleSetting"; +import { WritingStyleSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting"; export function SettingsTab() { return (
+ diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx new file mode 100644 index 0000000000..ae885a9dbb --- /dev/null +++ b/apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx @@ -0,0 +1,129 @@ +"use client"; + +import { useForm } from "react-hook-form"; +import { useAction } from "next-safe-action/hooks"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/Input"; +import { SettingCard } from "@/components/SettingCard"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { useAccount } from "@/providers/EmailAccountProvider"; +import { toastError, toastSuccess } from "@/components/Toast"; +import { useEmailAccountFull } from "@/hooks/useEmailAccountFull"; +import { Skeleton } from "@/components/ui/skeleton"; +import { LoadingContent } from "@/components/LoadingContent"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { + type SaveWritingStyleBody, + saveWritingStyleBody, +} from "@/utils/actions/user.validation"; +import { saveWritingStyleAction } from "@/utils/actions/user"; + +export function WritingStyleSetting() { + const { data, isLoading, error } = useEmailAccountFull(); + + const hasWritingStyle = !!data?.writingStyle; + + return ( + } + > + + + + + } + /> + ); +} + +function WritingStyleDialog({ + children, + currentWritingStyle, +}: { + children: React.ReactNode; + currentWritingStyle: string; +}) { + const { emailAccountId } = useAccount(); + const { mutate } = useEmailAccountFull(); + + const { + register, + formState: { errors }, + handleSubmit, + } = useForm({ + defaultValues: { writingStyle: currentWritingStyle }, + resolver: zodResolver(saveWritingStyleBody), + }); + + const { execute, isExecuting } = useAction( + saveWritingStyleAction.bind(null, emailAccountId), + { + onSuccess: () => { + toastSuccess({ + description: "Writing style saved!", + }); + }, + onError: (error) => { + toastError({ + description: + error.error.serverError ?? + "An unknown error occurred while saving your writing style", + }); + }, + onSettled: () => { + mutate(); + }, + }, + ); + + return ( + + {children} + + + Writing style + + Used to draft replies in your voice. + + + +
+ + +
+
+
+ ); +} diff --git a/apps/web/app/(app)/[emailAccountId]/organization/create/page.tsx b/apps/web/app/(app)/[emailAccountId]/organization/create/page.tsx index ffb1e072eb..416cd3cab9 100644 --- a/apps/web/app/(app)/[emailAccountId]/organization/create/page.tsx +++ b/apps/web/app/(app)/[emailAccountId]/organization/create/page.tsx @@ -16,6 +16,8 @@ import { slugify } from "@/utils/string"; import { useUser } from "@/hooks/useUser"; import { LoadingContent } from "@/components/LoadingContent"; import { useAccount } from "@/providers/EmailAccountProvider"; +import { PageHeader } from "@/components/PageHeader"; +import { PageWrapper } from "@/components/PageWrapper"; export default function CreateOrganizationPage() { const router = useRouter(); @@ -61,47 +63,36 @@ export default function CreateOrganizationPage() { ); return ( - -
-
-
-

Create Organization

-

- Set up your organization to collaborate with your team and manage - shared resources. -

-
+ + + +
+ - - + - - -
- -
-
-
-
-
+ + + + ); } diff --git a/apps/web/app/api/user/email-account/route.ts b/apps/web/app/api/user/email-account/route.ts index 46416e7dd7..053b27cf85 100644 --- a/apps/web/app/api/user/email-account/route.ts +++ b/apps/web/app/api/user/email-account/route.ts @@ -23,6 +23,7 @@ async function getEmailAccount({ emailAccountId }: { emailAccountId: string }) { calendarBookingLink: true, signature: true, includeReferralSignature: true, + writingStyle: true, }, }); diff --git a/apps/web/utils/actions/user.ts b/apps/web/utils/actions/user.ts index 4b9c95cb22..215be97a29 100644 --- a/apps/web/utils/actions/user.ts +++ b/apps/web/utils/actions/user.ts @@ -12,6 +12,7 @@ import { headers } from "next/headers"; import { saveAboutBody, saveSignatureBody, + saveWritingStyleBody, } from "@/utils/actions/user.validation"; import { clearLastEmailAccountCookie } from "@/utils/cookies.server"; import { aliasPosthogUser } from "@/utils/posthog"; @@ -36,6 +37,18 @@ export const saveSignatureAction = actionClient }); }); +export const saveWritingStyleAction = actionClient + .metadata({ name: "saveWritingStyle" }) + .inputSchema(saveWritingStyleBody) + .action( + async ({ parsedInput: { writingStyle }, ctx: { emailAccountId } }) => { + await prisma.emailAccount.update({ + where: { id: emailAccountId }, + data: { writingStyle }, + }); + }, + ); + export const resetAnalyticsAction = actionClient .metadata({ name: "resetAnalytics" }) .action(async ({ ctx: { emailAccountId } }) => { diff --git a/apps/web/utils/actions/user.validation.ts b/apps/web/utils/actions/user.validation.ts index 87258a0fa6..44e9817861 100644 --- a/apps/web/utils/actions/user.validation.ts +++ b/apps/web/utils/actions/user.validation.ts @@ -7,3 +7,8 @@ export const saveSignatureBody = z.object({ signature: z.string().max(10_000), }); export type SaveSignatureBody = z.infer; + +export const saveWritingStyleBody = z.object({ + writingStyle: z.string().max(2000), +}); +export type SaveWritingStyleBody = z.infer; diff --git a/version.txt b/version.txt index afd246d5e5..f6e6ad7f76 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v2.21.49 +v2.21.50