-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
93 changed files
with
3,260 additions
and
253 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
Oops, something went wrong.