Merge remote-tracking branch 'origin/main'

# Conflicts:
#	package.json
This commit is contained in:
killian-larcher
2024-11-17 19:14:30 +01:00
24 changed files with 1701 additions and 66 deletions
@@ -0,0 +1,40 @@
"use client"
import {Button} from "@/components/ui/button";
import {useState} from "react";
import {Loader2} from "lucide-react";
export type VariantButton = {
secondary: string
default: string
outline: string
ghost: string
link: string
destructive: string
}
export type ButtonWithConfirmProps = {
icon?: any,
text: string,
variant?: keyof VariantButton ,
className?: string,
onClick: () => void,
isPending? : boolean
};
export const ButtonWithLoading = (props: ButtonWithConfirmProps) => {
return(
<Button
onClick={() => {
props.onClick()
}}
variant={props.variant ? props.variant : "default"}
className={props.className}
>
{props.isPending && <Loader2 className="animate-spin mr-4" size={16}/>}
{props.text}
<>
{props.icon ? props.icon : null}
</>
</Button>
)
}
@@ -14,26 +14,50 @@ import {
EmailFormSchema,
EmailFormType
} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.schema";
import Link from "next/link";
import {PasswordInput} from "@/components/wrappers/Auth/PaswordInput/password-input";
import {
updateEmailSettingsAction
} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.action";
import {toast} from "sonner";
import {useRouter} from "next/navigation";
export type EmailFormProps = {
defaultValues?: EmailFormType;
}
export const EmailForm = (props: EmailFormProps) => {
const isCreate = !Boolean(props.defaultValues)
const form = useZodForm({
schema: EmailFormSchema,
defaultValues: props.defaultValues,
});
const router = useRouter();
const mutation = useMutation({
mutationFn: async (values: EmailFormType) => {
const updateEmailSettings = await updateEmailSettingsAction({name: "system", data: values})
const data = updateEmailSettings?.data?.data
if (updateEmailSettings?.serverError || !data) {
console.log(updateEmailSettings?.serverError);
toast.error(updateEmailSettings?.serverError);
return;
}
toast.success(`Success updating email informations`);
router.refresh()
}
})
return (
<TooltipProvider>
<Card>
<CardContent>
<Form form={form}
className="flex flex-col gap-4 mt-3"
onSubmit={async (values) => {
await mutation.mutateAsync(values);
@@ -42,6 +66,8 @@ export const EmailForm = (props: EmailFormProps) => {
<FormField
control={form.control}
name="smtpFrom"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>From Email *</FormLabel>
@@ -54,10 +80,81 @@ export const EmailForm = (props: EmailFormProps) => {
</FormItem>
)}
/>
<FormField
control={form.control}
name="smtpHost"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>Server Host *</FormLabel>
<FormControl>
<Input
placeholder={"ssl0.ovh.net"} {...field} />
</FormControl>
<FormDescription>{"Your email server host"}</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="smtpPort"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>Server Port *</FormLabel>
<FormControl>
<Input
placeholder={"465"} {...field} />
</FormControl>
<FormDescription>{"Your email server port (send)"}</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="smtpPassword"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<PasswordInput placeholder="Password" {...field}/>
</FormControl>
<FormDescription>{"Your email server password"}</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="smtpUser"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>User Email *</FormLabel>
<FormControl>
<Input
placeholder={"exemple@portabase.com"} {...field} />
</FormControl>
<FormDescription>{"The email server user"}</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<div className="flex justify-end gap-4">
<Button>
Save
</Button>
</div>
<Button>
Save
</Button>
</Form>
</CardContent>
</Card>
@@ -0,0 +1,31 @@
"use server"
import {userAction} from "@/safe-actions";
import {z} from "zod";
import {prisma} from "@/prisma";
import {EmailFormSchema} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/email-form.schema";
export const updateEmailSettingsAction = userAction
.schema(
z.object({
name: z.string(),
data: EmailFormSchema,
}
)
)
.action(async ({parsedInput, ctx}) => {
console.log("parsedInput", parsedInput.data)
const updatedSettings = await prisma.settings.update({
where: {
name: parsedInput.name,
},
data: parsedInput.data,
})
return {
data: updatedSettings,
}
})
@@ -1,12 +1,60 @@
import {EmailForm} from "@/components/wrappers/Dashboard/Settings/SettingsEmailTab/EmailForm/EmailForm";
import {Settings} from "@prisma/client";
import {Send} from "lucide-react";
import {ButtonWithLoading} from "@/components/wrappers/Button/ButtonWithLoading/ButtonWithLoading";
import {useMutation} from "@tanstack/react-query";
import {sendEmail} from "@/utils/email-helper";
import TestEmailSettings from "../../../../../../emails/TestEmailSettings";
import {render} from "@react-email/render";
import {toast} from "sonner";
export type SettingsEmailTabProps = {}
export const SettingsEmailTab = (props:SettingsEmailTabProps) => {
return(
<div>
<EmailForm/>
export type SettingsEmailTabProps = {
settings: Settings
}
export const SettingsEmailTab = (props: SettingsEmailTabProps) => {
const mutation = useMutation({
mutationFn: async () => {
const email = await sendEmail({
to: props.settings.smtpUser,
subject: "Portabase email test !",
html: await render(TestEmailSettings(), {})
});
if(email.response){
toast.success("Test Email Successfully sent !");
}
}
})
const handleSendMailTest = async () => {
console.log("Sending email test...");
await mutation.mutateAsync()
}
return (
<div className="flex flex-col h-full py-4">
<div className="flex gap-4 h-fit justify-between">
<h1>Settings for Portabase storage</h1>
{props.settings.smtpFrom && (
<ButtonWithLoading
isPending={mutation.isPending}
onClick={async () => {
await handleSendMailTest()
}}
icon={<Send/>}
text="Send email test"
/>
)}
</div>
<div className="mt-5">
<EmailForm defaultValues={props.settings.smtpFrom ? props.settings : null}/>
</div>
</div>
)
}
@@ -40,7 +40,7 @@ export const SettingsStorageTab = (props: SettingsStorageTabProps) => {
</div>
{isSwitched && (
<div className="mt-5">
<StorageS3Form/>
<StorageS3Form defaultValues={props.settings.s3EndPointUrl ? props.settings : null}/>
</div>
)}
</div>
@@ -22,6 +22,7 @@ export type S3FormProps = {
export const StorageS3Form = (props: S3FormProps) => {
const form = useZodForm({
schema: S3FormSchema,
defaultValues: props.defaultValues,
});
const mutation = useMutation({
mutationFn: async (values: S3FormType) => {
@@ -99,9 +100,12 @@ export const StorageS3Form = (props: S3FormProps) => {
</FormItem>
)}
/>
<Button>
Save
</Button>
<div className="flex justify-end gap-4">
<Button>
Save
</Button>
</div>
</Form>
</CardContent>
</Card>
@@ -37,7 +37,7 @@ export const SettingsTabs = (props: SettingsTabsProps) => {
<DataTableWithPagination columns={usersColumns} data={props.users}/>
</TabsContent>
<TabsContent value="email">
<SettingsEmailTab/>
<SettingsEmailTab settings={props.settings}/>
</TabsContent>
<TabsContent value="storage">
<SettingsStorageTab settings={props.settings}/>
@@ -15,11 +15,11 @@ export const SidebarMenuCustom = (props: SidebarMenuCustomProps) => {
const pathname = usePathname();
// Menu items.
const items = [
{
title: "Home",
url: "/",
icon: Home,
},
// {
// title: "Home",
// url: "/",
// icon: Home,
// },
{
title: "Agents",
url: "agents",