diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/actions/update-employee.ts b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/actions/update-employee.ts
index c46307f82b..35c33b422d 100644
--- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/actions/update-employee.ts
+++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/actions/update-employee.ts
@@ -10,98 +10,121 @@ import type { Departments } from "@comp/db/types";
import { headers } from "next/headers";
const schema = z.object({
- employeeId: z.string(),
- department: z.string().optional(),
- isActive: z.boolean().optional(),
+ employeeId: z.string(),
+ name: z.string().min(1, "Name cannot be empty").optional(),
+ email: z.string().email("Invalid email format").optional(),
+ department: z.string().optional(),
+ isActive: z.boolean().optional(),
});
export const updateEmployee = authActionClient
- .schema(schema)
- .metadata({
- name: "update-employee",
- track: {
- event: "update-employee",
- channel: "server",
- },
- })
- .action(
- async ({
- parsedInput,
- }): Promise<
- { success: true; data: any } | { success: false; error: any }
- > => {
- const { employeeId, department, isActive } = parsedInput;
-
- const session = await auth.api.getSession({
- headers: await headers(),
- });
-
- const organizationId = session?.session.activeOrganizationId;
-
- if (!organizationId) {
- return {
- success: false,
- error: appErrors.UNAUTHORIZED,
- };
- }
-
- try {
- const employee = await db.member.findUnique({
- where: {
- id: employeeId,
- organizationId,
- },
- });
-
- if (!employee) {
- return {
- success: false,
- error: appErrors.NOT_FOUND,
- };
- }
-
- // Build update data based on provided values
- const updateData: { department?: Departments; isActive?: boolean } = {};
-
- // Only include fields that were provided
- if (department !== undefined) {
- updateData.department = department as Departments;
- }
-
- if (isActive !== undefined) {
- updateData.isActive = isActive;
- }
-
- // Only update if there are changes
- if (Object.keys(updateData).length === 0) {
- return {
- success: true,
- data: employee,
- };
- }
-
- const updatedEmployee = await db.member.update({
- where: {
- id: employeeId,
- organizationId,
- },
- data: updateData,
- });
-
- // Revalidate related paths
- revalidatePath(`/${organizationId}/employees/${employeeId}`);
- revalidatePath(`/${organizationId}/employees`);
-
- return {
- success: true,
- data: updatedEmployee,
- };
- } catch (error) {
- console.error("Error updating employee:", error);
- return {
- success: false,
- error: appErrors.UNEXPECTED_ERROR,
- };
- }
- },
- );
+ .schema(schema)
+ .metadata({
+ name: "update-employee",
+ track: {
+ event: "update-employee",
+ channel: "server",
+ },
+ })
+ .action(
+ async ({
+ parsedInput,
+ }): Promise<
+ { success: true; data: any } | { success: false; error: any }
+ > => {
+ const { employeeId, name, email, department, isActive } = parsedInput;
+
+ const session = await auth.api.getSession({
+ headers: await headers(),
+ });
+
+ const organizationId = session?.session.activeOrganizationId;
+
+ if (!organizationId) {
+ return {
+ success: false,
+ error: appErrors.UNAUTHORIZED,
+ };
+ }
+
+ try {
+ const member = await db.member.findUnique({
+ where: {
+ id: employeeId,
+ organizationId,
+ },
+ });
+
+ if (!member) {
+ return {
+ success: false,
+ error: appErrors.NOT_FOUND,
+ };
+ }
+
+ const memberUpdateData: {
+ department?: Departments;
+ isActive?: boolean;
+ } = {};
+ const userUpdateData: { name?: string; email?: string } = {};
+
+ if (department !== undefined && department !== member.department) {
+ memberUpdateData.department = department as Departments;
+ }
+ if (isActive !== undefined && isActive !== member.isActive) {
+ memberUpdateData.isActive = isActive;
+ }
+ if (name !== undefined) {
+ userUpdateData.name = name;
+ }
+ if (email !== undefined) {
+ userUpdateData.email = email;
+ }
+
+ const hasMemberChanges = Object.keys(memberUpdateData).length > 0;
+ const hasUserChanges = Object.keys(userUpdateData).length > 0;
+
+ if (!hasMemberChanges && !hasUserChanges) {
+ return {
+ success: true,
+ data: member,
+ };
+ }
+
+ const updatedMember = await db.$transaction(async (tx) => {
+ if (hasUserChanges) {
+ await tx.user.update({
+ where: { id: member.userId },
+ data: userUpdateData,
+ });
+ }
+
+ if (hasMemberChanges) {
+ return tx.member.update({
+ where: {
+ id: employeeId,
+ organizationId,
+ },
+ data: memberUpdateData,
+ });
+ }
+
+ return member;
+ });
+
+ revalidatePath(`/${organizationId}/employees/${employeeId}`);
+ revalidatePath(`/${organizationId}/employees`);
+
+ return {
+ success: true,
+ data: updatedMember,
+ };
+ } catch (error) {
+ console.error("Error updating employee:", error);
+ return {
+ success: false,
+ error: appErrors.UNEXPECTED_ERROR,
+ };
+ }
+ }
+ );
diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/components/EmployeeDetails.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/components/EmployeeDetails.tsx
index 4817009ba7..0c932d01ef 100644
--- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/components/EmployeeDetails.tsx
+++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/employees/[employeeId]/components/EmployeeDetails.tsx
@@ -19,6 +19,16 @@ import {
CardHeader,
CardTitle,
} from "@comp/ui/card";
+import { cn } from "@comp/ui/cn";
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@comp/ui/form";
+import { Input } from "@comp/ui/input";
import {
Select,
SelectContent,
@@ -28,11 +38,14 @@ import {
} from "@comp/ui/select";
import { Skeleton } from "@comp/ui/skeleton";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@comp/ui/tabs";
+import { zodResolver } from "@hookform/resolvers/zod";
import { AlertCircle, CheckCircle2, Save } from "lucide-react";
import { useAction } from "next-safe-action/hooks";
import { redirect, useParams } from "next/navigation";
-import { useEffect, useState } from "react";
+import { useState } from "react";
+import { useForm } from "react-hook-form";
import { toast } from "sonner";
+import { z } from "zod";
import { useEmployeeDetails } from "../../all/hooks/useEmployee";
import { updateEmployee } from "../actions/update-employee";
@@ -51,6 +64,11 @@ const STATUS_OPTIONS: { value: EmployeeStatusType; label: string }[] = [
{ value: "inactive", label: "Inactive" },
];
+const EMPLOYEE_STATUS_HEX_COLORS: Record
Name
-{employee.user.name}
-- {formatDate(employee.createdAt.toISOString(), "MMM d, yyyy")} -
-+ {formatDate( + employee.createdAt.toISOString(), + "MMM d, yyyy", + )} +
+