Skip to content

Commit

Permalink
jos malo gotova employeeapp
Browse files Browse the repository at this point in the history
  • Loading branch information
komadiina committed Jan 28, 2025
1 parent 58ccae8 commit 025175e
Show file tree
Hide file tree
Showing 93 changed files with 3,260 additions and 253 deletions.
24 changes: 24 additions & 0 deletions employee-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions employee-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
"@stripe/react-stripe-js": "^3.1.1",
"@stripe/stripe-js": "^5.5.0",
"axios": "^1.7.9",
"papaparse": "^5.5.1",
"react": "^18.3.1",
"react-bootstrap": "^2.10.7",
"react-dom": "^18.3.1",
"react-dotenv": "^0.1.3",
"react-hook-form": "^7.54.2",
"react-router": "^7.1.3"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion employee-app/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
@tailwind utilities;

#root {
max-width: 1280px;
max-width: 1536px;
min-width: 1536px;
margin: 0 auto;
padding: 2rem;
text-align: center;
Expand Down
15 changes: 13 additions & 2 deletions employee-app/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import './App.css'
import { BrowserRouter, Routes, Route } from "react-router";
import Login from "./pages/Login.jsx";
import Register from "./pages/Register.jsx";
import EmployeeDashboard from './pages/EmployeeDashboard.jsx';
import ManufacturerInfo from './pages/info_displays/ManufacturerInfo.jsx';
import TransportationDeviceInfo from './pages/info_displays/TransportationDeviceInfo.jsx';
import ClientInfoDisplay from './pages/info_displays/ClientInfo.jsx';
import EmployeeInfoDisplay from './pages/info_displays/EmployeeInfo.jsx';

function App() {
return (
<BrowserRouter>

<Routes>
<Route path={"/"} element={<EmployeeDashboard />} />
<Route path={"/dashboard"} element={<EmployeeDashboard />} />
<Route path={"/login"} element={<Login />} />
<Route path={"/register"} element={<Register />} />

<Route path={"/manufacturers/:id"} element={<ManufacturerInfo />} />
<Route path={"/transportation-devices/:id"} element={<TransportationDeviceInfo />} />

<Route path={"/clients/:id"} element={<ClientInfoDisplay />} />
<Route path={"/employees/:id"} element={<EmployeeInfoDisplay />} />

<Route path={"*"} element={<h1>404</h1>} />
</Routes>
</BrowserRouter>
)
Expand Down
51 changes: 51 additions & 0 deletions employee-app/src/components/ManufacturerEntryForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState } from "react";
import api from "../utils/api";

export default function ManufacturerEntryForm() {
const [manufacturer, setManufacturer] = useState({});
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);

const handleChange = (event) => {
manufacturer[event.target.id] = event.target.value
setManufacturer(manufacturer)
}

const handleSubmit = async (ev) => {
const dto = {
name: manufacturer.name,
country: manufacturer.country,
address: manufacturer.address,
phone: manufacturer.phoneNumber,
fax: manufacturer.fax,
email: manufacturer.email
}

const response = await api.instance.post('/manufacturers', dto).catch(error => setError(error));
}

return (
<div className="flex flex-col justify-start gap-4 items-start">
<h1 className="px-2 font-bold">Add Manufacturer</h1>

<input id='name' className="minimal-input w-full" type="text" placeholder="Name" onChange={handleChange} />
<input id='country' className="minimal-input w-full" type="text" placeholder="Country" onChange={handleChange} />
<input id='address' className="minimal-input w-full" type="address" placeholder="Address" onChange={handleChange} />
<input id='phoneNumber' className="minimal-input w-full" type="tel" placeholder="Phone" onChange={handleChange} />
<input id='fax' className="minimal-input w-full" type="text" placeholder="Fax" onChange={handleChange} />
<input id='email' className="minimal-input w-full" type="fax" placeholder="Email" onChange={handleChange} />

<div className="flex flex-row items-start justify-start">
<button className="minimal-button" onClick={handleSubmit}>Submit</button>
{
error &&
<p className="text-red-500">Ooops!</p>
}
{
!error && success &&
<p className="text-green-500">Success!</p>
}
</div>
</div>
)
}
139 changes: 139 additions & 0 deletions employee-app/src/components/NewEmployeeForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import api from '../utils/api';

const NewEmployeeForm = () => {
const { register, handleSubmit, formState: { errors }, reset } = useForm();
const [submitError, setSubmitError] = useState(null);
const [submitSuccess, setSubmitSuccess] = useState(false);

const onSubmit = async (data) => {
try {
data = { ...data, userType: 'Employee' }
const response = await api.instance.post('/employees', data);
console.log('Employee created:', response.data);
setSubmitSuccess(true);
setSubmitError(null);
reset();
} catch (error) {
console.error('Error creating employee:', error);
setSubmitError('Failed to create employee. Please try again.');
setSubmitSuccess(false);
}
};

return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 w-full">
<div className='flex flex-col gap-2'>
<label htmlFor="firstName" className="text-xl items-start justify-start font-bold text-left">First Name</label>
<input
type="text"
id="firstName"
{...register('firstName', { required: 'First name is required' })}
className="minimal-input hover-highlight"
/>
{errors.firstName && <p className="my-1 text-lg italic text-red-600">{errors.firstName.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="lastName" className="text-xl items-start justify-start font-bold text-left">Last Name</label>
<input
type="text"
id="lastName"
{...register('lastName', { required: 'Last name is required' })}
className="minimal-input hover-highlight"
/>
{errors.lastName && <p className="my-1 text-lg italic text-red-600">{errors.lastName.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="username" className="text-xl items-start justify-start font-bold text-left">Username</label>
<input
type="text"
id="username"
{...register('username', { required: 'Username is required' })}
className="minimal-input hover-highlight"
/>
{errors.username && <p className="my-1 text-lg italic text-red-600">{errors.username.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="email" className="text-xl items-start justify-start font-bold text-left">Email</label>
<input
type="email"
id="email"
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "Invalid email address"
}
})}
className="minimal-input hover-highlight"
/>
{errors.email && <p className="my-1 text-lg italic text-red-600">{errors.email.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="password" className="text-xl items-start justify-start font-bold text-left">Password</label>
<input
type="password"
id="password"
{...register('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters long'
}
})}
className="minimal-input hover-highlight"
/>
{errors.password && <p className="my-1 text-lg italic text-red-600">{errors.password.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="phoneNumber" className="text-xl items-start justify-start font-bold text-left">Phone Number</label>
<input
type="tel"
id="phoneNumber"
{...register('phoneNumber', {
required: 'Phone number is required',
pattern: {
value: /^[0-9]+$/,
message: "Invalid phone number"
}
})}
className="minimal-input hover-highlight"
/>
{errors.phoneNumber && <p className="my-1 text-lg italic text-red-600">{errors.phoneNumber.message}</p>}
</div>

<div className='flex flex-col gap-2'>
<label htmlFor="role" className="text-xl items-start justify-start font-bold text-left">Role</label>
<select
id="role"
{...register('role', { required: 'Role is required' })}
className="minimal-input p-4 w-full hover-highlig"
>
<option className="text-black" value="">Select a role</option>
<option className="text-black" value="Administrator">Administrator</option>
<option className="text-black" value="Manager">Manager</option>
<option className="text-black" value="Operator">Operator</option>
</select>
{errors.role && <p className="my-1 text-lg italic text-red-600">{errors.role.message}</p>}
</div>

{submitError && <p className="text-sm text-red-600">{submitError}</p>}
{submitSuccess && <p className="text-sm text-green-600">Employee created successfully!</p>}

<button
type="submit"
className="minimal-input hover-highlight"
>
Create Employee
</button>
</form>
);
};

export default NewEmployeeForm;
88 changes: 88 additions & 0 deletions employee-app/src/components/tables/ClientTableGeneric.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useEffect, useState } from "react";
import api from "../../utils/api";
import { useNavigate } from "react-router";
import GenericTable from "./GenericTable";

export default function ClientTableGeneric() {
const [clients, setClients] = useState([]);
const [clientPage, setClientPage] = useState(0);
const [clientPageTotal, setClientPageTotal] = useState(0);

let navigate = useNavigate();

const commonColumns = [
{ 'key': 'firstName', 'label': 'First Name' },
{ 'key': 'lastName', 'label': 'Last Name' },
{ 'key': 'username', 'label': 'Username' },
{ 'key': 'email', 'label': 'Email' },
{ 'key': 'active', 'label': 'Active' },
{ 'key': 'phoneNumber', 'label': 'Phone' },
{ 'key': 'userType', 'label': 'Type' },
]

const clientColumns = [
...commonColumns,
{ 'key': 'idCardNumber', 'label': 'ID Card' },
{ 'key': 'passportID', 'label': 'Passport' },
{ 'key': 'balance', 'label': 'Balance' }
];


const fetchClients = async () => {
try {
const [clientsResponse] = await Promise.all([api.instance.get(`/clients?page=${clientPage}&limit=10`)]);
setClients(clientsResponse.data.content.map(c => ({ ...c, active: c.active ? 'Active' : 'Inactive' })));

setClientPageTotal(clientsResponse.data.totalPages);
setClientPage(clientsResponse.data.pageable.pageNumber);
} catch (error) {
console.error('Error fetching clients:', error);
}
}

useEffect(() => {
fetchClients();
}, [clientPage])

const onSortClient = (key) => {
const sortedClients = [...clients];
sortedClients.sort((a, b) => a[key] > b[key] ? 1 : -1);
setClients(sortedClients);
};

const onToggleClientActivity = async (item) => {
if (window.confirm("Are you sure?")) {
try {

await api.instance.post(`/clients/toggle-active/${item.id}`);
await fetchClients();
} catch (error) {
console.error('Error updating client:', error);
}
}
};

const onInfoClient = (item) => {
console.log(item);
navigate(`/clients/${item.id}`);
};

return (
clients &&
<div className="flex flex-col gap-4 card items-start justify-start">
<h1 className="px-2 font-bold text-xl">Clients</h1>
<GenericTable
columns={clientColumns}
data={clients}
onInfo={onInfoClient}
onToggleActivity={onToggleClientActivity}
onSort={onSortClient}
currentPage={clientPage}
totalPages={clientPageTotal}
onNextPage={() => setClientPage(prev => Math.min(prev + 1, clientPageTotal - 1))}
onPrevPage={() => setClientPage(prev => Math.max(prev - 1, 0))}
clickableRow={false}
/>
</div>
)
}
Loading

0 comments on commit 025175e

Please sign in to comment.