diff --git a/src/app/dashboard/(auth)/users/_modals/DeleteModal/DeleteModal.tsx b/src/app/dashboard/(auth)/users/_modals/DeleteModal/DeleteModal.tsx
deleted file mode 100644
index f19fcd9..0000000
--- a/src/app/dashboard/(auth)/users/_modals/DeleteModal/DeleteModal.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-"use client";
-import { UserFormData } from "@/features/dashboard/users/formSchemas/userFormDataSchema";
-import { useRouter } from "next/navigation";
-import React, { useState } from "react";
-import {
- Avatar,
- Button,
- Center,
- Flex,
- Modal,
- ScrollArea,
- Text,
- Stack,
- TextInput,
- Title,
-} from "@mantine/core";
-import deleteUser from "@/features/dashboard/users/actions/deleteUser";
-import { showNotification } from "@/utils/notifications";
-
-interface Props {
- data: UserFormData;
-}
-
-export default function DeleteModal(props: Props) {
- const router = useRouter();
-
- const [isSubmitting, setSubmitting] = useState(false);
-
- /**
- * Closes the modal. It won't close if a submission is in progress.
- */
- const closeModal = () => {
- if (isSubmitting) return;
- router.replace("?");
- };
-
- const confirmAction = () => {
- setSubmitting(true)
- deleteUser(props.data.id)
- .then((response) => {
- if (response.success){
- showNotification(response.message);
- router.replace("?")
- return;
- } else {
- showNotification(response.message, "error")
- }
- })
- .catch(() => {
- //TODO: Handle Error
- })
- .finally(() => {
- setSubmitting(false)
- })
- }
-
- return (
-
-
- Are you sure you want to delete user{" "}
-
- {props.data.name}
-
- ? This action is irreversible.
-
- {/* Buttons */}
-
-
- }
- type="submit"
- color="red"
- loading={isSubmitting}
- onClick={confirmAction}
- >
- Delete User
-
-
-
- );
-}
diff --git a/src/app/dashboard/(auth)/users/_modals/DeleteModal/index.ts b/src/app/dashboard/(auth)/users/_modals/DeleteModal/index.ts
deleted file mode 100644
index a4052f8..0000000
--- a/src/app/dashboard/(auth)/users/_modals/DeleteModal/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import DeleteModal from "./DeleteModal";
-
-export default DeleteModal;
diff --git a/src/app/dashboard/(auth)/users/_modals/DetailModal/DetailModal.tsx b/src/app/dashboard/(auth)/users/_modals/DetailModal/DetailModal.tsx
deleted file mode 100644
index 9003280..0000000
--- a/src/app/dashboard/(auth)/users/_modals/DetailModal/DetailModal.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import { FormModal } from '..'
-import { UserFormData } from '@/features/dashboard/users/formSchemas/userFormDataSchema'
-
-interface Props {
- data: UserFormData
-}
-
-export default function DetailModal(props: Props) {
- return
-}
diff --git a/src/app/dashboard/(auth)/users/_modals/DetailModal/index.ts b/src/app/dashboard/(auth)/users/_modals/DetailModal/index.ts
deleted file mode 100644
index 2871960..0000000
--- a/src/app/dashboard/(auth)/users/_modals/DetailModal/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import DetailModal from "./DetailModal";
-
-export default DetailModal;
diff --git a/src/app/dashboard/(auth)/users/_modals/EditModal/EditModal.tsx b/src/app/dashboard/(auth)/users/_modals/EditModal/EditModal.tsx
deleted file mode 100644
index 9e8ff6a..0000000
--- a/src/app/dashboard/(auth)/users/_modals/EditModal/EditModal.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import { FormModal } from '..'
-import { UserFormData } from '@/features/dashboard/users/formSchemas/userFormDataSchema'
-
-interface Props {
- data: UserFormData
-}
-
-export default function EditModal(props: Props) {
- return
-}
diff --git a/src/app/dashboard/(auth)/users/_modals/EditModal/index.ts b/src/app/dashboard/(auth)/users/_modals/EditModal/index.ts
deleted file mode 100644
index 1dfd72f..0000000
--- a/src/app/dashboard/(auth)/users/_modals/EditModal/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import EditModal from "./EditModal";
-
-export default EditModal;
diff --git a/src/app/dashboard/(auth)/users/_modals/FormModal/FormModal.tsx b/src/app/dashboard/(auth)/users/_modals/FormModal/FormModal.tsx
deleted file mode 100644
index f2e6a0a..0000000
--- a/src/app/dashboard/(auth)/users/_modals/FormModal/FormModal.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-"use client";
-import React, { useState } from "react";
-import { useForm } from "@mantine/form";
-import { useRouter } from "next/navigation";
-import {
- Avatar,
- Button,
- Center,
- Flex,
- Modal,
- ScrollArea,
- Stack,
- TextInput,
- Title,
-} from "@mantine/core";
-import { TbDeviceFloppy } from "react-icons/tb";
-import editUser from "@/features/dashboard/users/actions/editUser";
-import userFormDataSchema, {
- UserFormData,
-} from "@/features/dashboard/users/formSchemas/userFormDataSchema";
-import { showNotification } from "@/utils/notifications";
-import stringToColorHex from "@/utils/stringToColorHex";
-import { zodResolver } from "@mantine/form";
-
-interface Props {
- readonly?: boolean;
- modalTitle: string;
- data: UserFormData;
-}
-
-export default function FormModal(props: Props) {
- const router = useRouter();
-
- const [isSubmitting, setSubmitting] = useState(false);
-
- const form = useForm({
- initialValues: props.data,
- validate: zodResolver(userFormDataSchema),
- });
-
- /**
- * Closes the modal. It won't close if a submission is in progress.
- */
- const closeModal = () => {
- if (isSubmitting) return;
- router
- .replace("?")
- };
-
- /**
- * Handles the form submission.
- *
- * @param data The data from the form.
- */
- const handleSubmit = (data: UserFormData) => {
- setSubmitting(true);
- editUser(data)
- .then((response) => {
- if (response.success) {
- showNotification(response.message);
- router.replace("?")
- return;
- } else {
- if (response.errors) {
- form.setErrors(response.errors);
- return;
- }
- showNotification(response.message, "error");
- return;
- }
- })
- .catch(() => {
- //TODO: Handle Error
- })
- .finally(() => {
- setSubmitting(false);
- });
- };
-
- return (
- {props.modalTitle}}
- scrollAreaComponent={ScrollArea.Autosize}
- >
-
-
- );
-}
diff --git a/src/app/dashboard/(auth)/users/_modals/FormModal/index.ts b/src/app/dashboard/(auth)/users/_modals/FormModal/index.ts
deleted file mode 100644
index f10c3b0..0000000
--- a/src/app/dashboard/(auth)/users/_modals/FormModal/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import FormModal from "./FormModal";
-
-export default FormModal;
diff --git a/src/app/dashboard/(auth)/users/_modals/index.ts b/src/app/dashboard/(auth)/users/_modals/index.ts
deleted file mode 100644
index 0a33e94..0000000
--- a/src/app/dashboard/(auth)/users/_modals/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { default as DeleteModal } from "./DeleteModal"
-export { default as DetailModal } from "./DetailModal"
-export { default as EditModal } from "./EditModal"
-export { default as FormModal } from "./FormModal"
diff --git a/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx b/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx
deleted file mode 100644
index ca0596c..0000000
--- a/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-"use client";
-import React from "react";
-
-import {
- flexRender,
- getCoreRowModel,
- useReactTable,
-} from "@tanstack/react-table";
-import columns, { UserRow } from "./columns";
-import { Table, Text } from "@mantine/core";
-
-interface Props {
- users: UserRow[];
-}
-
-export default function UsersTable({ users }: Props) {
- const table = useReactTable({
- data: users,
- columns,
- getCoreRowModel: getCoreRowModel(),
- defaultColumn: {
- cell: (props) => {props.getValue() as React.ReactNode},
- },
- });
-
- return (
-
- {/* Thead */}
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => (
-
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
-
- ))}
-
- ))}
-
-
- {/* TBody */}
-
- {table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => (
-
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
-
- ))}
-
- ))}
-
-
- );
-}
diff --git a/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx b/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx
deleted file mode 100644
index 4c5aaf7..0000000
--- a/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { createColumnHelper } from "@tanstack/react-table";
-import Link from "next/link";
-import { ActionIcon, Anchor, Avatar, Badge, Flex, Group, Text, Tooltip } from "@mantine/core";
-import { TbEye, TbPencil, TbTrash } from "react-icons/tb";
-import stringToColorHex from "@/utils/stringToColorHex";
-
-export interface UserRow {
- id: string,
- name: string | null,
- email: string | null,
- photoUrl: string | null,
-}
-
-const columnHelper = createColumnHelper()
-
-const columns = [
- columnHelper.display({
- id: "sequence",
- header: "#",
- cell: props => props.row.index + 1,
- size: 1
- }),
-
- columnHelper.accessor('name', {
- header: "Name",
- cell: (props) =>
- {props.getValue()?.[0].toUpperCase()}
- {props.getValue()}
-
- }),
-
- columnHelper.accessor('email', {
- header: "Email",
- cell: (props) => {props.getValue()}
- }),
-
- columnHelper.display({
- id: "status",
- header: "Status",
- cell: (props) => Active
- }),
-
- columnHelper.display({
- id: 'actions',
- header: "Actions",
- size: 10,
- meta: {
- className: "w-fit"
- },
- cell: (props) =>
-
- {/* Detail */}
-
-
-
-
-
-
- {/* Edit */}
-
-
-
-
-
-
- {/* Delete */}
-
-
-
-
-
-
- })
-];
-
-export default columns;
diff --git a/src/modules/userManagement/actions/upsertUser.ts b/src/modules/userManagement/actions/upsertUser.ts
index f1e8911..1521c81 100644
--- a/src/modules/userManagement/actions/upsertUser.ts
+++ b/src/modules/userManagement/actions/upsertUser.ts
@@ -3,12 +3,15 @@
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
import prisma from "@/db";
import { revalidatePath } from "next/cache";
-import userFormDataSchema, { UserFormData } from "../formSchemas/userFormSchema";
+import userFormDataSchema, {
+ UserFormData,
+} from "../formSchemas/userFormSchema";
import checkPermission from "@/modules/dashboard/services/checkPermission";
import unauthorized from "@/modules/dashboard/utils/unauthorized";
import DashboardError from "@/modules/dashboard/errors/DashboardError";
import handleCatch from "@/modules/dashboard/utils/handleCatch";
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
+import hashPassword from "@/modules/auth/utils/hashPassword";
/**
* Upserts a user based on the provided UserFormData.
@@ -34,32 +37,37 @@ export default async function upsertUser(
const validatedFields = userFormDataSchema.safeParse(data);
if (!validatedFields.success) {
throw new DashboardError({
- errorCode: "INVALID_FORM_DATA",
- formErrors: mapObjectToFirstValue(validatedFields.error.flatten().fieldErrors)
- })
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: mapObjectToFirstValue(
+ validatedFields.error.flatten().fieldErrors
+ ),
+ });
}
const userData = {
- id: validatedFields.data.id ? validatedFields.data.id : undefined,
+ id: validatedFields.data.id ? validatedFields.data.id : undefined,
name: validatedFields.data.name,
- photoProfile: validatedFields.data.photoProfileUrl ?? "",
- email: validatedFields.data.email
+ photoProfile: validatedFields.data.photoProfileUrl ?? "",
+ email: validatedFields.data.email,
};
+ const passwordHash = await hashPassword(validatedFields.data.password!);
// Database operation
if (isInsert) {
- if (await prisma.user.findFirst({
- where: {
- email: userData.email
- }
- })){
- throw new DashboardError({
- errorCode: "INVALID_FORM_DATA",
- formErrors: {
- email: "The user is already exists"
- }
- })
- }
- await prisma.user.create({ data: userData });
+ if (
+ await prisma.user.findFirst({
+ where: {
+ email: userData.email,
+ },
+ })
+ ) {
+ throw new DashboardError({
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: {
+ email: "The user is already exists",
+ },
+ });
+ }
+ await prisma.user.create({ data: { ...userData, passwordHash } });
} else {
await prisma.user.update({
where: { id: validatedFields.data.id! },
@@ -78,6 +86,6 @@ export default async function upsertUser(
}.`,
};
} catch (error) {
- return handleCatch(error)
+ return handleCatch(error);
}
}
diff --git a/src/modules/userManagement/formSchemas/userFormSchema.ts b/src/modules/userManagement/formSchemas/userFormSchema.ts
index 24b1f0e..c080296 100644
--- a/src/modules/userManagement/formSchemas/userFormSchema.ts
+++ b/src/modules/userManagement/formSchemas/userFormSchema.ts
@@ -1,17 +1,19 @@
import { z } from "zod";
export interface UserFormData {
- id: string;
+ id: string | undefined;
name: string;
photoProfileUrl: string;
email: string;
+ password: string | undefined
}
const userFormDataSchema = z.object({
- id: z.string().nullable(),
+ id: z.string().optional(),
name: z.string(),
photoProfileUrl: z.union([z.string(), z.null()]),
email: z.string().email(),
+ password: z.string().min(8).optional(),
});
export default userFormDataSchema;
diff --git a/src/modules/userManagement/modals/UserFormModal.tsx b/src/modules/userManagement/modals/UserFormModal.tsx
index bfe1090..b4c20ed 100644
--- a/src/modules/userManagement/modals/UserFormModal.tsx
+++ b/src/modules/userManagement/modals/UserFormModal.tsx
@@ -15,6 +15,7 @@ import {
Alert,
Center,
Avatar,
+ PasswordInput,
} from "@mantine/core";
import { useForm, zodResolver } from "@mantine/form";
import { useRouter } from "next/navigation";
@@ -55,6 +56,7 @@ export default function UserFormModal(props: ModalProps) {
email: "",
name: "",
photoProfileUrl: "",
+ password: "",
},
validate: zodResolver(userFormDataSchema),
validateInputOnChange: false,
@@ -128,7 +130,7 @@ export default function UserFormModal(props: ModalProps) {
onClose={closeModal}
title={props.title}
scrollAreaComponent={ScrollArea.Autosize}
- size="xl"
+ size="md"
>