Added more to add user

This commit is contained in:
Mitchell Magro 2025-07-14 18:56:59 +02:00
parent 7dd4323ebe
commit f0ddb809d7
6 changed files with 193 additions and 106 deletions

View File

@ -35,16 +35,28 @@ export const users = [
twoFactorCondition: "required", twoFactorCondition: "required",
twoFactorCredentials: [], twoFactorCredentials: [],
}, },
{ ];
export async function GET() {
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const { firstName, lastName, email, phone, role } = body;
// Add the new user to the existing users array (in-memory, not persistent)
const bodytoAdd = {
merchantId: 100987998, merchantId: 100987998,
mame: "Jacob", mame: "Jacob",
id: "382eed15-1e21-41fa-b1f3-0c1adb3af714", id: "382eed15-1e21-41fa-b1f3-0c1adb3af714",
username: "lsterence", username: "lsterence",
firstName: "Terence", firstName,
lastName: "User", lastName,
email: "terence@omegasys.eu", email,
phone: "", phone,
jobTitle: "", jobTitle: "",
role,
enabled: true, enabled: true,
authorities: ["ROLE_IIN", "ROLE_FIRST_APPROVER", "ROLE_RULES_ADMIN"], authorities: ["ROLE_IIN", "ROLE_FIRST_APPROVER", "ROLE_RULES_ADMIN"],
allowedMerchantIds: [100987998], allowedMerchantIds: [100987998],
@ -60,68 +72,8 @@ export const users = [
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"], requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
twoFactorCondition: "required", twoFactorCondition: "required",
twoFactorCredentials: [], twoFactorCredentials: [],
},
];
export async function GET() {
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
// Use the first user as a template
const templateUser = users[0];
// Create the new user by spreading the template and then the body (body fields override template)
const newUser = {
...templateUser,
...body,
id:
typeof crypto !== "undefined" && crypto.randomUUID
? crypto.randomUUID()
: Math.random().toString(36).substring(2, 15),
created: new Date().toISOString(),
}; };
users.push(bodytoAdd);
users.push(newUser); return NextResponse.json(users, { status: 201 });
return NextResponse.json(newUser, { status: 201 });
} }
// To call the POST function from the client side, you can use fetch like this:
/*
Example usage in a React component or any client-side JS:
const createUser = async (userData) => {
const res = await fetch('/api/dashboard/admin/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!res.ok) {
// handle error
throw new Error('Failed to create user');
}
const newUser = await res.json();
return newUser;
};
// Usage:
createUser({
username: "newuser",
firstName: "New",
lastName: "User",
email: "newuser@example.com",
// ...other fields as needed
}).then(user => {
console.log('Created user:', user);
}).catch(err => {
console.error(err);
});
*/

View File

@ -0,0 +1,53 @@
.modal__overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.modal {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.2);
position: relative;
min-width: 320px;
max-width: 90vw;
max-height: 90vh;
overflow: auto;
padding: 2rem 1.5rem 1.5rem 1.5rem;
display: flex;
flex-direction: column;
}
.modal__close {
position: absolute;
top: 1rem;
right: 1rem;
background: transparent;
border: none;
font-size: 2rem;
line-height: 1;
cursor: pointer;
color: #888;
transition: color 0.2s;
&:hover,
&:focus {
color: #333;
outline: none;
}
}
.modal__body {
// Example element block for modal content
margin-top: 1rem;
font-size: 1rem;
color: #222;
width: 500px;
}

View File

@ -0,0 +1,48 @@
import React from "react";
import "./Modal.scss";
interface ModalProps {
open: boolean;
onClose: () => void;
children: React.ReactNode;
className?: string;
overlayClassName?: string;
title?: string;
}
const Modal: React.FC<ModalProps> = ({
open,
onClose,
children,
title,
className = "",
}) => {
if (!open) return null;
return (
<div
className={"modal__overlay"}
onClick={onClose}
data-testid="modal-overlay"
>
<div
className={`modal${className ? " " + className : ""}`}
onClick={(e) => e.stopPropagation()}
data-testid="modal-content"
>
<button
className="modal__close"
onClick={onClose}
aria-label="Close"
type="button"
>
&times;
</button>
{title && <h2 className="modal__title">{title}</h2>}
<div className={"modal__body"}>{children}</div>
</div>
</div>
);
};
export default Modal;

View File

@ -1,16 +1,22 @@
"use client"; "use client";
import React from "react"; import React, { useState } from "react";
import { Card, CardContent, Typography, Stack } from "@mui/material"; import { Card, CardContent, Typography, Stack } from "@mui/material";
import { IUser } from "./interfaces"; import { IUser } from "./interfaces";
import UserRoleCard from "@/app/features/UserRoles/UserRoleCard"; import UserRoleCard from "@/app/features/UserRoles/UserRoleCard";
import UserTopBar from "@/app/features/UserRoles/AddUser/AddUser";
import EditUser from "@/app/features/UserRoles/EditUser/EditUser";
import Modal from "@/app/components/Modal/Modal";
interface UsersProps { interface UsersProps {
users: IUser[]; users: IUser[];
} }
const Users: React.FC<UsersProps> = ({ users }) => { const Users: React.FC<UsersProps> = ({ users }) => {
const [showAddUser, setShowAddUser] = useState(false);
return ( return (
<div> <div>
<UserTopBar onAddUser={() => setShowAddUser(true)} />
{users.map((user: IUser) => ( {users.map((user: IUser) => (
<Card key={user.id} sx={{ mb: 2 }}> <Card key={user.id} sx={{ mb: 2 }}>
<CardContent> <CardContent>
@ -35,6 +41,14 @@ const Users: React.FC<UsersProps> = ({ users }) => {
</CardContent> </CardContent>
</Card> </Card>
))} ))}
<Modal
open={showAddUser}
onClose={() => setShowAddUser(false)}
title="Add User"
>
<EditUser />
</Modal>
</div> </div>
); );
}; };

View File

@ -1,46 +1,34 @@
.edit-user { .add-user {
margin-top: 30px; position: sticky;
display: flex; top: 40px;
flex-wrap: wrap;
gap: 16px;
input {
flex: 1 1 20%;
min-width: 150px;
box-sizing: border-box;
padding: 8px;
font-size: 1rem;
border-radius: 4px;
border: 1px solid #ccc;
outline: none;
transition: border-color 0.3s ease;
&:focus {
border-color: #0070f3;
}
}
&__button-container {
flex-basis: 100%;
width: 100%; width: 100%;
background: #fff;
z-index: 10;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 1rem;
padding: 1rem 0.5rem;
border-bottom: 1px solid #eee;
button { &__button {
flex-basis: 100%; padding: 0.5rem 1rem;
margin-top: 16px; border: none;
padding: 10px 0;
font-size: 1rem;
border-radius: 4px; border-radius: 4px;
width: 100px;
cursor: pointer; cursor: pointer;
font-size: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
} }
button:first-child { &__button--primary {
color: var(--button-primary); background: #1976d2;
border-color: var(--button-primary); color: #fff;
}
button:last-child {
color: var(--button-secondary);
border-color: var(--button-secondary);
margin-left: 8;
} }
&__button--secondary {
background: #e0e0e0;
color: #333;
} }
} }

View File

@ -0,0 +1,32 @@
import { Add } from "@mui/icons-material";
import React from "react";
import "./AddUser.scss";
const AddUser: React.FC<{
onAddUser?: () => void;
onExport?: () => void;
}> = ({ onAddUser, onExport }) => {
return (
<div className="add-user">
<button
type="button"
onClick={onAddUser}
className="add-user__button add-user__button--primary"
>
<Add />
Add User
</button>
<button
type="button"
onClick={onExport}
className="add-user__button add-user__button--secondary"
disabled
title="Export to Excel (coming soon)"
>
Export to Excel
</button>
</div>
);
};
export default AddUser;