Autosave: 20260413-132151

This commit is contained in:
Flatlogic Bot 2026-04-13 13:21:52 +00:00
parent c9732c5db8
commit da86c68992
16 changed files with 70 additions and 850 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View File

@ -240,9 +240,19 @@ module.exports = class Payroll_runsDBApi {
output.payroll_line_items_payroll_run = await payroll_runs.getPayroll_line_items_payroll_run({ output.payroll_line_items_payroll_run = await Promise.all(
transaction (await payroll_runs.getPayroll_line_items_payroll_run({
}); transaction
})).map(async (payrollLineItem) => {
const payrollLineItemOutput = payrollLineItem.get({ plain: true });
payrollLineItemOutput.employee = await payrollLineItem.getEmployee({
transaction,
});
return payrollLineItemOutput;
}),
);

View File

@ -5,6 +5,11 @@ const db = require('../db/models');
const { wrapAsync } = require('../helpers'); const { wrapAsync } = require('../helpers');
const { Op } = require('sequelize'); const { Op } = require('sequelize');
const getInclusiveDateRange = (startDate, endDate) => ({
start: new Date(`${startDate}T00:00:00.000Z`),
end: new Date(`${endDate}T23:59:59.999Z`),
});
router.post('/preview', passport.authenticate('jwt', { session: false }), wrapAsync(async (req, res) => { router.post('/preview', passport.authenticate('jwt', { session: false }), wrapAsync(async (req, res) => {
const { startDate, endDate } = req.body; const { startDate, endDate } = req.body;
@ -12,11 +17,13 @@ router.post('/preview', passport.authenticate('jwt', { session: false }), wrapAs
return res.status(400).send('startDate and endDate are required'); return res.status(400).send('startDate and endDate are required');
} }
const { start, end } = getInclusiveDateRange(startDate, endDate);
// Find job logs in range that are not paid // Find job logs in range that are not paid
const jobLogs = await db.job_logs.findAll({ const jobLogs = await db.job_logs.findAll({
where: { where: {
work_date: { work_date: {
[Op.between]: [new Date(startDate), new Date(endDate)] [Op.between]: [start, end]
}, },
status: { status: {
[Op.ne]: 'paid' [Op.ne]: 'paid'
@ -85,11 +92,13 @@ router.post('/generate', passport.authenticate('jwt', { session: false }), wrapA
return res.status(400).send('startDate and endDate are required'); return res.status(400).send('startDate and endDate are required');
} }
const { start, end } = getInclusiveDateRange(startDate, endDate);
// Find job logs // Find job logs
const jobLogs = await db.job_logs.findAll({ const jobLogs = await db.job_logs.findAll({
where: { where: {
work_date: { work_date: {
[Op.between]: [new Date(startDate), new Date(endDate)] [Op.between]: [start, end]
}, },
status: { status: {
[Op.ne]: 'paid' [Op.ne]: 'paid'

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -218,53 +218,8 @@ export const loadColumns = async (
}, },
{
field: 'odometer_start',
headerName: 'OdometerStart',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
field: 'odometer_end',
headerName: 'OdometerEnd',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
field: 'job_address',
headerName: 'JobAddress',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{ {
field: 'status', field: 'status',
headerName: 'Status', headerName: 'Status',

View File

@ -84,28 +84,12 @@ const menuAside: MenuAsideItem[] = [
icon: 'mdiLinkVariant' in icon ? icon['mdiLinkVariant' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon: 'mdiLinkVariant' in icon ? icon['mdiLinkVariant' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
permissions: 'UPDATE_USERS' permissions: 'UPDATE_USERS'
}, },
{
href: '/chemical_products/chemical_products-list',
label: 'Chemical products',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
icon: 'mdiFlask' in icon ? icon['mdiFlask' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
permissions: 'UPDATE_USERS'
},
{ {
href: '/job_logs/job_logs-list', href: '/job_logs/job_logs-list',
label: 'All Job Logs', label: 'All Job Logs',
icon: 'mdiClipboardTextClock' in icon ? icon['mdiClipboardTextClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon: 'mdiClipboardTextClock' in icon ? icon['mdiClipboardTextClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
permissions: 'UPDATE_USERS' permissions: 'UPDATE_USERS'
}, },
{
href: '/job_chemical_usages/job_chemical_usages-list',
label: 'Job chemical usages',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
icon: 'mdiFlaskOutline' in icon ? icon['mdiFlaskOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
permissions: 'UPDATE_USERS'
},
{ {
href: '/payroll_runs/payroll_runs-list', href: '/payroll_runs/payroll_runs-list',
label: 'Payroll runs', label: 'Payroll runs',

View File

@ -32,9 +32,7 @@ const Dashboard = () => {
const [vehicles, setVehicles] = React.useState(loadingMessage); const [vehicles, setVehicles] = React.useState(loadingMessage);
const [pay_types, setPay_types] = React.useState(loadingMessage); const [pay_types, setPay_types] = React.useState(loadingMessage);
const [employee_pay_types, setEmployee_pay_types] = React.useState(loadingMessage); const [employee_pay_types, setEmployee_pay_types] = React.useState(loadingMessage);
const [chemical_products, setChemical_products] = React.useState(loadingMessage);
const [job_logs, setJob_logs] = React.useState(loadingMessage); const [job_logs, setJob_logs] = React.useState(loadingMessage);
const [job_chemical_usages, setJob_chemical_usages] = React.useState(loadingMessage);
const [payroll_runs, setPayroll_runs] = React.useState(loadingMessage); const [payroll_runs, setPayroll_runs] = React.useState(loadingMessage);
const [payroll_line_items, setPayroll_line_items] = React.useState(loadingMessage); const [payroll_line_items, setPayroll_line_items] = React.useState(loadingMessage);
@ -58,8 +56,8 @@ const Dashboard = () => {
return; return;
} }
const entities = ['users','roles','permissions','customers','vehicles','pay_types','employee_pay_types','chemical_products','job_logs','job_chemical_usages','payroll_runs','payroll_line_items',]; const entities = ['users','roles','permissions','customers','vehicles','pay_types','employee_pay_types','job_logs','payroll_runs','payroll_line_items',];
const fns = [setUsers,setRoles,setPermissions,setCustomers,setVehicles,setPay_types,setEmployee_pay_types,setChemical_products,setJob_logs,setJob_chemical_usages,setPayroll_runs,setPayroll_line_items,]; const fns = [setUsers,setRoles,setPermissions,setCustomers,setVehicles,setPay_types,setEmployee_pay_types,setJob_logs,setPayroll_runs,setPayroll_line_items,];
const requests = entities.map((entity, index) => { const requests = entities.map((entity, index) => {
@ -355,34 +353,6 @@ const Dashboard = () => {
</div> </div>
</Link>} </Link>}
{hasPermission(currentUser, 'READ_CHEMICAL_PRODUCTS') && <Link href={'/chemical_products/chemical_products-list'}>
<div
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
>
<div className="flex justify-between align-center">
<div>
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
Chemical products
</div>
<div className="text-3xl leading-tight font-semibold">
{chemical_products}
</div>
</div>
<div>
<BaseIcon
className={`${iconsColor}`}
w="w-16"
h="h-16"
size={48}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
path={'mdiFlask' in icon ? icon['mdiFlask' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
/>
</div>
</div>
</div>
</Link>}
{hasPermission(currentUser, 'READ_JOB_LOGS') && <Link href={'/job_logs/job_logs-list'}> {hasPermission(currentUser, 'READ_JOB_LOGS') && <Link href={'/job_logs/job_logs-list'}>
<div <div
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`} className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
@ -411,34 +381,6 @@ const Dashboard = () => {
</div> </div>
</Link>} </Link>}
{hasPermission(currentUser, 'READ_JOB_CHEMICAL_USAGES') && <Link href={'/job_chemical_usages/job_chemical_usages-list'}>
<div
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}
>
<div className="flex justify-between align-center">
<div>
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
Job chemical usages
</div>
<div className="text-3xl leading-tight font-semibold">
{job_chemical_usages}
</div>
</div>
<div>
<BaseIcon
className={`${iconsColor}`}
w="w-16"
h="h-16"
size={48}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
path={'mdiFlaskOutline' in icon ? icon['mdiFlaskOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable}
/>
</div>
</div>
</div>
</Link>}
{hasPermission(currentUser, 'READ_PAYROLL_RUNS') && <Link href={'/payroll_runs/payroll_runs-list'}> {hasPermission(currentUser, 'READ_PAYROLL_RUNS') && <Link href={'/payroll_runs/payroll_runs-list'}>
<div <div
className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`} className={`${corners !== 'rounded-full'? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}

View File

@ -270,7 +270,6 @@ const EditJob_logs = () => {
odometer_start: '',
@ -298,7 +297,6 @@ const EditJob_logs = () => {
odometer_end: '',
@ -320,7 +318,6 @@ const EditJob_logs = () => {
'job_address': '',
@ -875,146 +872,6 @@ const EditJob_logs = () => {
></Field> ></Field>
</FormField> </FormField>
<FormField
label="OdometerStart"
>
<Field
type="number"
name="odometer_start"
placeholder="OdometerStart"
/>
</FormField>
<FormField
label="OdometerEnd"
>
<Field
type="number"
name="odometer_end"
placeholder="OdometerEnd"
/>
</FormField>
<FormField
label="JobAddress"
>
<Field
name="job_address"
placeholder="JobAddress"
/>
</FormField>
<FormField label="Status" labelFor="status"> <FormField label="Status" labelFor="status">
<Field name="status" id="status" component="select"> <Field name="status" id="status" component="select">

View File

@ -271,7 +271,6 @@ const EditJob_logsPage = () => {
odometer_start: '',
@ -299,7 +298,6 @@ const EditJob_logsPage = () => {
odometer_end: '',
@ -321,7 +319,6 @@ const EditJob_logsPage = () => {
'job_address': '',
@ -867,146 +864,6 @@ const EditJob_logsPage = () => {
></Field> ></Field>
</FormField> </FormField>
<FormField
label="OdometerStart"
>
<Field
type="number"
name="odometer_start"
placeholder="OdometerStart"
/>
</FormField>
<FormField
label="OdometerEnd"
>
<Field
type="number"
name="odometer_end"
placeholder="OdometerEnd"
/>
</FormField>
<FormField
label="JobAddress"
>
<Field
name="job_address"
placeholder="JobAddress"
/>
</FormField>
<FormField label="Status" labelFor="status"> <FormField label="Status" labelFor="status">
<Field name="status" id="status" component="select"> <Field name="status" id="status" component="select">

View File

@ -34,8 +34,7 @@ const Job_logsTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'JobAddress', title: 'job_address'},{label: 'NotesToAdmin', title: 'notes_to_admin'}, const [filters] = useState([{label: 'NotesToAdmin', title: 'notes_to_admin'},
{label: 'OdometerStart', title: 'odometer_start', number: 'true'},{label: 'OdometerEnd', title: 'odometer_end', number: 'true'},
{label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'}, {label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'},
{label: 'WorkDate', title: 'work_date', date: 'true'}, {label: 'WorkDate', title: 'work_date', date: 'true'},

View File

@ -163,7 +163,6 @@ const initialValues = {
odometer_start: '',
@ -179,7 +178,6 @@ const initialValues = {
odometer_end: '',
@ -192,7 +190,6 @@ const initialValues = {
job_address: '',
@ -527,136 +524,6 @@ const Job_logsNew = () => {
<FormField label="Vehicle" labelFor="vehicle"> <FormField label="Vehicle" labelFor="vehicle">
<Field name="vehicle" id="vehicle" component={SelectField} options={[]} itemRef={'vehicles'}></Field> <Field name="vehicle" id="vehicle" component={SelectField} options={[]} itemRef={'vehicles'}></Field>
</FormField> </FormField>
<FormField
label="OdometerStart"
>
<Field
type="number"
name="odometer_start"
placeholder="OdometerStart"
/>
</FormField>
<FormField
label="OdometerEnd"
>
<Field
type="number"
name="odometer_end"
placeholder="OdometerEnd"
/>
</FormField>
<FormField
label="JobAddress"
>
<Field
name="job_address"
placeholder="JobAddress"
/>
</FormField>
<FormField label="Status" labelFor="status"> <FormField label="Status" labelFor="status">
<Field name="status" id="status" component="select"> <Field name="status" id="status" component="select">

View File

@ -34,8 +34,7 @@ const Job_logsTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'JobAddress', title: 'job_address'},{label: 'NotesToAdmin', title: 'notes_to_admin'}, const [filters] = useState([{label: 'NotesToAdmin', title: 'notes_to_admin'},
{label: 'OdometerStart', title: 'odometer_start', number: 'true'},{label: 'OdometerEnd', title: 'odometer_end', number: 'true'},
{label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'}, {label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'},
{label: 'WorkDate', title: 'work_date', date: 'true'}, {label: 'WorkDate', title: 'work_date', date: 'true'},

View File

@ -421,127 +421,6 @@ const Job_logsView = () => {
</div> </div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>OdometerStart</p>
<p>{job_logs?.odometer_start || 'No data'}</p>
</div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>OdometerEnd</p>
<p>{job_logs?.odometer_end || 'No data'}</p>
</div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>JobAddress</p>
<p>{job_logs?.job_address}</p>
</div>
<div className={'mb-4'}> <div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Status</p> <p className={'block font-bold mb-2'}>Status</p>
<p>{job_logs?.status ?? 'No data'}</p> <p>{job_logs?.status ?? 'No data'}</p>
@ -595,65 +474,6 @@ const Job_logsView = () => {
<>
<p className={'block font-bold mb-2'}>Job_chemical_usages JobLog</p>
<CardBox
className='mb-6 border border-gray-300 rounded overflow-hidden'
hasTable
>
<div className='overflow-x-auto'>
<table>
<thead>
<tr>
<th>QuantityUsed</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{job_logs.job_chemical_usages_job_log && Array.isArray(job_logs.job_chemical_usages_job_log) &&
job_logs.job_chemical_usages_job_log.map((item: any) => (
<tr key={item.id} onClick={() => router.push(`/job_chemical_usages/job_chemical_usages-view/?id=${item.id}`)}>
<td data-label="quantity_used">
{ item.quantity_used }
</td>
<td data-label="notes">
{ item.notes }
</td>
</tr>
))}
</tbody>
</table>
</div>
{!job_logs?.job_chemical_usages_job_log?.length && <div className={'text-center py-4'}>No data</div>}
</CardBox>
</>

View File

@ -1,4 +1,4 @@
import { mdiPencil, mdiPlus, mdiTrashCan } from '@mdi/js'; import { mdiPencil } from '@mdi/js';
import Head from 'next/head'; import Head from 'next/head';
import React, { ReactElement, useEffect, useState } from 'react'; import React, { ReactElement, useEffect, useState } from 'react';
import CardBox from '../components/CardBox'; import CardBox from '../components/CardBox';
@ -8,7 +8,7 @@ import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton
import JobLogPayPreview from '../components/JobLogPayPreview'; import JobLogPayPreview from '../components/JobLogPayPreview';
import { getPageTitle } from '../config'; import { getPageTitle } from '../config';
import { Field, Form, Formik, FieldArray } from 'formik'; import { Field, Form, Formik } from 'formik';
import FormField from '../components/FormField'; import FormField from '../components/FormField';
import BaseDivider from '../components/BaseDivider'; import BaseDivider from '../components/BaseDivider';
import BaseButtons from '../components/BaseButtons'; import BaseButtons from '../components/BaseButtons';
@ -27,11 +27,13 @@ const LogWorkPage = () => {
useEffect(() => { useEffect(() => {
if (currentUser?.id) { if (currentUser?.id) {
axios.get(`/employee_pay_types?employee=${currentUser.id}&active=true`) axios
.get(`/employee_pay_types?employee=${currentUser.id}&active=true`)
.then((res) => { .then((res) => {
if (res.data && res.data.rows) { if (res.data && res.data.rows) {
// Ensure we are extracting the inner pay_type relation from employee_pay_types const payTypes = res.data.rows
const payTypes = res.data.rows.map((row: any) => row.pay_type).filter(Boolean); .map((row: any) => row.pay_type)
.filter(Boolean);
setAssignedPayTypes(payTypes); setAssignedPayTypes(payTypes);
} }
}) })
@ -40,7 +42,7 @@ const LogWorkPage = () => {
}, [currentUser]); }, [currentUser]);
const initialValues = { const initialValues = {
work_date: new Date().toISOString().slice(0, 16), work_date: new Date().toISOString().slice(0, 10),
employee: currentUser?.id || '', employee: currentUser?.id || '',
customer: '', customer: '',
hours_conducted: '', hours_conducted: '',
@ -48,12 +50,8 @@ const LogWorkPage = () => {
workersCompClass: '', workersCompClass: '',
pay_type: '', pay_type: '',
vehicle: '', vehicle: '',
odometer_start: '',
odometer_end: '',
job_address: '',
status: 'submitted', status: 'submitted',
notes_to_admin: '', notes_to_admin: '',
chemical_usages: [],
}; };
const handleSubmit = async (data: any) => { const handleSubmit = async (data: any) => {
@ -72,10 +70,10 @@ const LogWorkPage = () => {
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
<Formik initialValues={initialValues} onSubmit={(values) => handleSubmit(values)}> <Formik initialValues={initialValues} onSubmit={(values) => handleSubmit(values)}>
{({ values }) => ( {() => (
<Form> <Form>
<FormField label="Work Date"> <FormField label="Work Date">
<Field type="datetime-local" name="work_date" /> <Field type="date" name="work_date" />
</FormField> </FormField>
<FormField label="Customer" labelFor="customer"> <FormField label="Customer" labelFor="customer">
<Field name="customer" id="customer" placeholder="Enter customer name" /> <Field name="customer" id="customer" placeholder="Enter customer name" />
@ -87,7 +85,14 @@ const LogWorkPage = () => {
<Field type="number" name="client_paid" placeholder="Amount" /> <Field type="number" name="client_paid" placeholder="Amount" />
</FormField> </FormField>
<FormField label="Worker's Comp Class" labelFor="workersCompClass"> <FormField label="Worker's Comp Class" labelFor="workersCompClass">
<Field name="workersCompClass" id="workersCompClass" component={SelectField} options={[]} itemRef={"workers_comp_classes"} showField={"name"} /> <Field
name="workersCompClass"
id="workersCompClass"
component={SelectField}
options={[]}
itemRef={'workers_comp_classes'}
showField={'name'}
/>
</FormField> </FormField>
<FormField label="Pay Type" labelFor="pay_type"> <FormField label="Pay Type" labelFor="pay_type">
<Field name="pay_type" id="pay_type" as="select"> <Field name="pay_type" id="pay_type" as="select">
@ -101,68 +106,18 @@ const LogWorkPage = () => {
</FormField> </FormField>
<JobLogPayPreview payTypeOptions={assignedPayTypes} /> <JobLogPayPreview payTypeOptions={assignedPayTypes} />
<FormField label="Vehicle" labelFor="vehicle"> <FormField label="Vehicle" labelFor="vehicle">
<Field name="vehicle" id="vehicle" component={SelectField} options={[]} itemRef={'vehicles'} /> <Field
</FormField> name="vehicle"
<FormField label="Odometer Start"> id="vehicle"
<Field type="number" name="odometer_start" placeholder="Start" /> component={SelectField}
</FormField> options={[]}
<FormField label="Odometer End"> itemRef={'vehicles'}
<Field type="number" name="odometer_end" placeholder="End" /> />
</FormField>
<FormField label="Job Address">
<Field name="job_address" placeholder="Address" />
</FormField> </FormField>
<FormField label="Notes to Admin" hasTextareaHeight> <FormField label="Notes to Admin" hasTextareaHeight>
<Field name="notes_to_admin" as="textarea" placeholder="Notes..." /> <Field name="notes_to_admin" as="textarea" placeholder="Notes..." />
</FormField> </FormField>
<BaseDivider />
<h3 className="text-lg font-bold mb-4">Chemical Usage (Optional)</h3>
<FieldArray name="chemical_usages">
{({ push, remove }) => (
<div>
{values.chemical_usages.map((usage, index) => (
<div key={index} className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4 items-end border p-4 rounded-lg bg-gray-50 dark:bg-slate-800">
<FormField label="Chemical Product" labelFor={`chemical_usages.${index}.chemical_product`}>
<Field
name={`chemical_usages.${index}.chemical_product`}
id={`chemical_usages.${index}.chemical_product`}
component={SelectField}
itemRef="chemical_products"
showField="name"
/>
</FormField>
<FormField label="Quantity Used" labelFor={`chemical_usages.${index}.quantity_used`}>
<Field
type="number"
name={`chemical_usages.${index}.quantity_used`}
id={`chemical_usages.${index}.quantity_used`}
placeholder="e.g. 5.5"
step="0.01"
/>
</FormField>
<div className="mb-4">
<BaseButton
type="button"
color="danger"
label="Remove"
icon={mdiTrashCan}
onClick={() => remove(index)}
/>
</div>
</div>
))}
<BaseButton
type="button"
color="success"
label="Add Chemical"
icon={mdiPlus}
onClick={() => push({ chemical_product: '', quantity_used: '' })}
/>
</div>
)}
</FieldArray>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type="submit" color="info" label="Submit Work Log" /> <BaseButton type="submit" color="info" label="Submit Work Log" />

View File

@ -30,10 +30,20 @@ const Payroll_runsView = () => {
const { id } = router.query; const { id } = router.query;
function removeLastCharacter(str) { function removeLastCharacter(str) {
console.log(str,`str`)
return str.slice(0, -1); return str.slice(0, -1);
} }
function formatEmployeeName(employee) {
if (!employee) return 'No data';
const fullName = [employee.firstName, employee.lastName]
.filter(Boolean)
.join(' ')
.trim();
return fullName || employee.email || 'No data';
}
useEffect(() => { useEffect(() => {
dispatch(fetch({ id })); dispatch(fetch({ id }));
}, [dispatch, id]); }, [dispatch, id]);
@ -292,72 +302,28 @@ const Payroll_runsView = () => {
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Employee</th>
<th>TotalHours</th> <th>TotalHours</th>
<th>GrossPay</th> <th>GrossPay</th>
<th>TotalCommissionBase</th> <th>TotalCommissionBase</th>
<th>TotalClientPaid</th>
<th>Summary</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{payroll_runs.payroll_line_items_payroll_run && Array.isArray(payroll_runs.payroll_line_items_payroll_run) && {payroll_runs.payroll_line_items_payroll_run && Array.isArray(payroll_runs.payroll_line_items_payroll_run) &&
payroll_runs.payroll_line_items_payroll_run.map((item: any) => ( payroll_runs.payroll_line_items_payroll_run.map((item: any) => (
<tr key={item.id} onClick={() => router.push(`/payroll_line_items/payroll_line_items-view/?id=${item.id}`)}> <tr key={item.id} onClick={() => router.push(`/payroll_line_items/payroll_line_items-view/?id=${item.id}`)}>
<td data-label="employee">
{formatEmployeeName(item.employee)}
</td>
<td data-label="total_hours"> <td data-label="total_hours">
{ item.total_hours } { item.total_hours }
</td> </td>
<td data-label="gross_pay"> <td data-label="gross_pay">
{ item.gross_pay } { item.gross_pay }
</td> </td>
<td data-label="total_commission_base"> <td data-label="total_commission_base">
{ item.total_commission_base } { item.total_commission_base }
</td> </td>
<td data-label="total_client_paid">
{ item.total_client_paid }
</td>
<td data-label="summary">
{ item.summary }
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>