feat: enhance platform dashboard UX and add security controls

- Move Add Company button to Companies card header for better context
- Add smart Save Changes button that only appears when data is modified
- Implement navigation protection with unsaved changes warnings
- Add company status checks to prevent suspended companies from processing data
- Fix platform dashboard showing incorrect user counts
- Add dark mode toggle to platform interface
- Add copy-to-clipboard for generated credentials
- Fix cookie conflicts between regular and platform auth
- Add invitedBy and invitedAt tracking fields to User model
- Improve overall platform management workflow and security
This commit is contained in:
2025-06-28 18:19:25 +02:00
parent 2f2c358e67
commit 36ed8259b1
12 changed files with 524 additions and 137 deletions

View File

@ -66,7 +66,7 @@ export async function POST(
data: {
name,
email,
hashedPassword,
password: hashedPassword,
role,
companyId,
invitedBy: session.user.email,

View File

@ -40,6 +40,7 @@ export async function GET(request: NextRequest) {
select: {
sessions: true,
imports: true,
users: true,
},
},
},
@ -75,23 +76,72 @@ export async function POST(request: NextRequest) {
}
const body = await request.json();
const { name, csvUrl, csvUsername, csvPassword, status = "TRIAL" } = body;
const {
name,
csvUrl,
csvUsername,
csvPassword,
adminEmail,
adminName,
adminPassword,
maxUsers = 10,
status = "TRIAL"
} = body;
if (!name || !csvUrl) {
return NextResponse.json({ error: "Name and CSV URL required" }, { status: 400 });
}
const company = await prisma.company.create({
data: {
name,
csvUrl,
csvUsername: csvUsername || null,
csvPassword: csvPassword || null,
status,
},
if (!adminEmail || !adminName) {
return NextResponse.json({ error: "Admin email and name required" }, { status: 400 });
}
// Generate password if not provided
const finalAdminPassword = adminPassword || `Temp${Math.random().toString(36).slice(2, 8)}!`;
// Hash the admin password
const bcrypt = await import("bcryptjs");
const hashedPassword = await bcrypt.hash(finalAdminPassword, 12);
// Create company and admin user in a transaction
const result = await prisma.$transaction(async (tx) => {
// Create the company
const company = await tx.company.create({
data: {
name,
csvUrl,
csvUsername: csvUsername || null,
csvPassword: csvPassword || null,
maxUsers,
status,
},
});
// Create the admin user
const adminUser = await tx.user.create({
data: {
email: adminEmail,
password: hashedPassword,
name: adminName,
role: "ADMIN",
companyId: company.id,
invitedBy: session.user.email || "platform",
invitedAt: new Date(),
},
});
return { company, adminUser, generatedPassword: adminPassword ? null : finalAdminPassword };
});
return NextResponse.json({ company }, { status: 201 });
return NextResponse.json({
company: result.company,
adminUser: {
email: result.adminUser.email,
name: result.adminUser.name,
role: result.adminUser.role,
},
generatedPassword: result.generatedPassword,
}, { status: 201 });
} catch (error) {
console.error("Platform company creation error:", error);
return NextResponse.json({ error: "Internal server error" }, { status: 500 });