mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # src/components/wrappers/dashboard/Organization/organization-combobox.tsx
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
"use client";
|
||||
|
||||
import {Card, CardContent} from "@/components/ui/card";
|
||||
import {
|
||||
FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useZodForm
|
||||
} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Form} from "@/components/ui/form"
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {TooltipProvider} from "@/components/ui/tooltip";
|
||||
|
||||
import {
|
||||
EmailFormSchema,
|
||||
EmailFormType
|
||||
} from "@/components/wrappers/dashboard/admin/AdminEmailTab/EmailForm/email-form.schema";
|
||||
import Link from "next/link";
|
||||
import {PasswordInput} from "@/components/wrappers/auth/PaswordInput/password-input";
|
||||
import {
|
||||
updateEmailSettingsAction
|
||||
} from "@/components/wrappers/dashboard/admin/AdminEmailTab/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);
|
||||
}}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="smtpFrom"
|
||||
defaultValue=""
|
||||
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>From Email *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={"exemple@portabase.com"} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>{"The email from where the email will be send"}</FormDescription>
|
||||
<FormMessage/>
|
||||
</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>
|
||||
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
@@ -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/admin/AdminEmailTab/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,
|
||||
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
import {z} from "zod";
|
||||
|
||||
export const EmailFormSchema = z.object({
|
||||
smtpPassword: z.string(),
|
||||
smtpFrom: z.string(),
|
||||
smtpHost: z.string(),
|
||||
smtpPort: z.string(),
|
||||
smtpUser: z.string(),
|
||||
});
|
||||
|
||||
export type EmailFormType = z.infer<typeof EmailFormSchema>;
|
||||
@@ -0,0 +1,61 @@
|
||||
import {EmailForm} from "@/components/wrappers/dashboard/admin/AdminEmailTab/EmailForm/EmailForm";
|
||||
import {Settings} from "@prisma/client";
|
||||
import {Send} from "lucide-react";
|
||||
import {ButtonWithLoading} from "@/components/wrappers/common/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";
|
||||
import HelloEmail from "../../../../../../emails/HelloEmail";
|
||||
|
||||
|
||||
|
||||
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",
|
||||
html: await render(TestEmailSettings(),{})
|
||||
});
|
||||
if(email.response){
|
||||
toast.success("Test Email Successfully sent !");
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const handleSendMailTest = async () => {
|
||||
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 email setup</h1>
|
||||
{props.settings.smtpFrom && (
|
||||
<ButtonWithLoading
|
||||
isPending={mutation.isPending}
|
||||
onClick={async () => {
|
||||
await handleSendMailTest()
|
||||
}}
|
||||
icon={<Send/>}
|
||||
text="Send email test"
|
||||
size="default"
|
||||
/>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<EmailForm defaultValues={props.settings.smtpFrom ? props.settings : null}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert";
|
||||
import {Info, Send, ShieldCheck} from "lucide-react";
|
||||
import {Switch} from "@/components/ui/switch";
|
||||
import {Label} from "@/components/ui/label";
|
||||
import {StorageS3Form} from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/StorageS3Form";
|
||||
import {useState} from "react";
|
||||
import {Settings} from "@prisma/client";
|
||||
import {ButtonWithLoading} from "@/components/wrappers/common/button/ButtonWithLoading/ButtonWithLoading";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {checkConnexionToS3} from "@/features/upload/public/upload.action";
|
||||
import {toast} from "sonner";
|
||||
import {updateUserAction} from "@/components/wrappers/dashboard/Profile/UserForm/user-form.action";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {
|
||||
updateStorageSettingsAction
|
||||
} from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
|
||||
|
||||
|
||||
export type SettingsStorageTabProps = {
|
||||
settings: Settings
|
||||
}
|
||||
|
||||
export const SettingsStorageTab = (props: SettingsStorageTabProps) => {
|
||||
const router = useRouter()
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const result = await checkConnexionToS3()
|
||||
if(result.error){
|
||||
toast.error("An error occured during the connexion !")
|
||||
}else{
|
||||
toast.success("Connexion succeed!")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const [isSwitched, setIsSwitched] = useState<boolean>(props.settings.storage !== "local");
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: () => updateStorageSettingsAction({name: "system", data: {storage: isSwitched ? "s3": "local"}}),
|
||||
onSuccess: () => {
|
||||
toast.success(`Settings updated successfully.`);
|
||||
router.refresh()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(`An error occurred while updating settings information.`);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const HandleSwitchStorage = async () => {
|
||||
setIsSwitched(!isSwitched);
|
||||
await updateMutation.mutateAsync()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full py-4">
|
||||
<h1>Settings for Portabase storage</h1>
|
||||
<Alert className="mt-3">
|
||||
<Info className="h-4 w-4"/>
|
||||
<AlertTitle>Informations</AlertTitle>
|
||||
<AlertDescription>
|
||||
Actually you can only store you data in one place : s3 compatible or in local.
|
||||
For exemple you cannot choose to store images in one place and .dump files in another.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<div className="flex flex-col h-full py-4 ">
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Label htmlFor="storage-mode">Storage Mode (Local/s3 compatible)</Label>
|
||||
<Switch
|
||||
checked={isSwitched}
|
||||
onCheckedChange={async () => {
|
||||
await HandleSwitchStorage()
|
||||
}}
|
||||
id="storage-mode"/>
|
||||
</div>
|
||||
<div>
|
||||
<ButtonWithLoading
|
||||
size={"default"}
|
||||
disabled={!isSwitched}
|
||||
isPending={mutation.isPending}
|
||||
onClick={async () => {
|
||||
await mutation.mutateAsync()
|
||||
}}
|
||||
icon={<ShieldCheck />}
|
||||
text="Test connexion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isSwitched && (
|
||||
<div className="mt-5">
|
||||
<StorageS3Form defaultValues={props.settings.s3EndPointUrl ? props.settings : null}/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
"use client";
|
||||
|
||||
import {Card, CardContent} from "@/components/ui/card";
|
||||
import {
|
||||
FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useZodForm
|
||||
} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Form} from "@/components/ui/form"
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {TooltipProvider} from "@/components/ui/tooltip";
|
||||
|
||||
import {
|
||||
S3FormSchema,
|
||||
S3FormType
|
||||
} from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {toast} from "sonner";
|
||||
import {
|
||||
updateS3SettingsAction
|
||||
} from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
|
||||
|
||||
export type S3FormProps = {
|
||||
defaultValues?: S3FormType;
|
||||
}
|
||||
|
||||
export const StorageS3Form = (props: S3FormProps) => {
|
||||
const form = useZodForm({
|
||||
schema: S3FormSchema,
|
||||
defaultValues: props.defaultValues,
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: async (values: S3FormType) => {
|
||||
console.log(values)
|
||||
const updateS3Settings = await updateS3SettingsAction({name: "system", data: values})
|
||||
const data = updateS3Settings?.data?.data
|
||||
if (updateS3Settings?.serverError || !data) {
|
||||
console.log(updateS3Settings?.serverError);
|
||||
toast.error(updateS3Settings?.serverError);
|
||||
return;
|
||||
}
|
||||
toast.success(`Success updating storage 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);
|
||||
}}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="s3EndPointUrl"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Endpoint Url *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={"s3.eu-west-3.amazonaws.com"} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>{"Your s3 compatible url"}</FormDescription>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="s3AccessKeyId"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Access Key *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={"The access key token"} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>{"Add your access key"}</FormDescription>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="s3SecretAccessKey"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Secret Key *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={"The secret key token"} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>{"Add your secret key"}</FormDescription>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="S3BucketName"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bucket name *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={"my-bucket"} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>{"The bucket name where you want to store your data"}</FormDescription>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex justify-end gap-4">
|
||||
|
||||
<Button>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
"use server"
|
||||
import {userAction} from "@/safe-actions";
|
||||
import {z} from "zod";
|
||||
import {prisma} from "@/prisma";
|
||||
import {
|
||||
S3FormSchema,
|
||||
StorageSwitchSchema
|
||||
} from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema";
|
||||
|
||||
|
||||
export const updateS3SettingsAction = userAction
|
||||
.schema(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
data: S3FormSchema,
|
||||
}
|
||||
)
|
||||
)
|
||||
.action(async ({parsedInput, ctx}) => {
|
||||
const updatedSettings = await prisma.settings.update({
|
||||
where: {
|
||||
name: parsedInput.name,
|
||||
},
|
||||
data: parsedInput.data,
|
||||
})
|
||||
return {
|
||||
data: updatedSettings,
|
||||
}
|
||||
})
|
||||
|
||||
export const updateStorageSettingsAction = userAction
|
||||
.schema(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
data: StorageSwitchSchema,
|
||||
}
|
||||
)
|
||||
)
|
||||
.action(async ({parsedInput, ctx}) => {
|
||||
const updatedSettings = await prisma.settings.update({
|
||||
where: {
|
||||
name: parsedInput.name,
|
||||
},
|
||||
data: parsedInput.data,
|
||||
})
|
||||
return {
|
||||
data: updatedSettings,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import {z} from "zod";
|
||||
|
||||
export const S3FormSchema = z.object({
|
||||
s3EndPointUrl: z.string(),
|
||||
s3AccessKeyId: z.string(),
|
||||
s3SecretAccessKey: z.string(),
|
||||
S3BucketName: z.string(),
|
||||
});
|
||||
|
||||
export type S3FormType = z.infer<typeof S3FormSchema>;
|
||||
|
||||
|
||||
export const StorageSwitchSchema = z.object({
|
||||
storage: z.string(),
|
||||
})
|
||||
|
||||
export type StorageType= z.infer<typeof StorageSwitchSchema>;
|
||||
@@ -0,0 +1,42 @@
|
||||
"use client"
|
||||
|
||||
import {User, Settings} from "@prisma/client";
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
||||
import {SettingsEmailTab} from "@/components/wrappers/dashboard/admin/AdminEmailTab/SettingsEmailTab";
|
||||
import {SettingsStorageTab} from "@/components/wrappers/dashboard/admin/AdminStorageTab/SettingsStorageTab";
|
||||
import {AdminUsersTable} from "@/components/wrappers/dashboard/admin/admin-user-table";
|
||||
|
||||
|
||||
export type AdminTabsProps = {
|
||||
currentUser: User;
|
||||
users: User[];
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
export const AdminTabs = (props: AdminTabsProps) => {
|
||||
|
||||
const {currentUser, users, settings} = props;
|
||||
|
||||
return (
|
||||
|
||||
<Tabs defaultValue="users">
|
||||
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger className="w-full " value="users">Users</TabsTrigger>
|
||||
<TabsTrigger className="w-full " value="email">Email</TabsTrigger>
|
||||
<TabsTrigger className="w-full " value="storage">Storage</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="users">
|
||||
<AdminUsersTable currentUser={currentUser} users={users}/>
|
||||
</TabsContent>
|
||||
<TabsContent value="email">
|
||||
<SettingsEmailTab settings={settings}/>
|
||||
</TabsContent>
|
||||
<TabsContent value="storage">
|
||||
<SettingsStorageTab settings={settings}/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import {flexRender, Row, RowData} from "@tanstack/react-table";
|
||||
|
||||
import {User} from "@prisma/client";
|
||||
import {DataTableWithPagination} from "@/components/wrappers/table/data-table-with-pagination";
|
||||
import {usersColumns} from "@/components/wrappers/dashboard/Settings/SettingsUsersTab/columns-users";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
import {cn} from "@/lib/utils";
|
||||
|
||||
export type AdminUsersTableProps = {
|
||||
currentUser: User;
|
||||
users: User[]
|
||||
}
|
||||
|
||||
export const AdminUsersTable = (props: AdminUsersTableProps) => {
|
||||
|
||||
const {currentUser, users} = props;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full py-4">
|
||||
<div className="flex gap-4 h-fit justify-between">
|
||||
<h1>List of Portabase's users</h1>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<DataTableWithPagination
|
||||
columns={usersColumns}
|
||||
data={users}
|
||||
DataTable={UsersDataTable}
|
||||
dataTableProps={{currentUser}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export type usersDataTableProps = {
|
||||
currentUser: User;
|
||||
table: any,
|
||||
}
|
||||
|
||||
export const UsersDataTable = ({currentUser, table}: usersDataTableProps) => {
|
||||
|
||||
return (
|
||||
<div className="rounded-md border w-full ">
|
||||
<Table className="w-full">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
)
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row: Row<User>) => (
|
||||
<TableRow
|
||||
className={cn(row.original.id === currentUser.id ? "opacity-40 pointer-events-none" : "")}
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={table.getAllColumns().length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user