version 1.2

This commit is contained in:
Flatlogic Bot 2025-08-15 19:54:24 +00:00
parent 0b3a035811
commit 1387fa9cf0
23 changed files with 511 additions and 173 deletions

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,9 @@ module.exports = class BookingsDBApi {
start_date: data.start_date || null, start_date: data.start_date || null,
end_date: data.end_date || null, end_date: data.end_date || null,
status: data.status || null, status: data.status || null,
vehiclenumber: data.vehiclenumber || null,
phone: data.phone || null,
email: data.email || null,
importHash: data.importHash || null, importHash: data.importHash || null,
createdById: currentUser.id, createdById: currentUser.id,
updatedById: currentUser.id, updatedById: currentUser.id,
@ -45,6 +48,9 @@ module.exports = class BookingsDBApi {
start_date: item.start_date || null, start_date: item.start_date || null,
end_date: item.end_date || null, end_date: item.end_date || null,
status: item.status || null, status: item.status || null,
vehiclenumber: item.vehiclenumber || null,
phone: item.phone || null,
email: item.email || null,
importHash: item.importHash || null, importHash: item.importHash || null,
createdById: currentUser.id, createdById: currentUser.id,
updatedById: currentUser.id, updatedById: currentUser.id,
@ -78,6 +84,13 @@ module.exports = class BookingsDBApi {
if (data.status !== undefined) updatePayload.status = data.status; if (data.status !== undefined) updatePayload.status = data.status;
if (data.vehiclenumber !== undefined)
updatePayload.vehiclenumber = data.vehiclenumber;
if (data.phone !== undefined) updatePayload.phone = data.phone;
if (data.email !== undefined) updatePayload.email = data.email;
updatePayload.updatedById = currentUser.id; updatePayload.updatedById = currentUser.id;
await bookings.update(updatePayload, { transaction }); await bookings.update(updatePayload, { transaction });
@ -213,6 +226,31 @@ module.exports = class BookingsDBApi {
}; };
} }
if (filter.vehiclenumber) {
where = {
...where,
[Op.and]: Utils.ilike(
'bookings',
'vehiclenumber',
filter.vehiclenumber,
),
};
}
if (filter.phone) {
where = {
...where,
[Op.and]: Utils.ilike('bookings', 'phone', filter.phone),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('bookings', 'email', filter.email),
};
}
if (filter.calendarStart && filter.calendarEnd) { if (filter.calendarStart && filter.calendarEnd) {
where = { where = {
...where, ...where,

View File

@ -0,0 +1,49 @@
module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.addColumn(
'bookings',
'vehiclenumber',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.removeColumn('bookings', 'vehiclenumber', {
transaction,
});
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -0,0 +1,47 @@
module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.addColumn(
'bookings',
'phone',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.removeColumn('bookings', 'phone', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -0,0 +1,47 @@
module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.addColumn(
'bookings',
'email',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.removeColumn('bookings', 'email', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -32,6 +32,18 @@ module.exports = function (sequelize, DataTypes) {
values: ['Pending', 'Inspected', 'Cancelled'], values: ['Pending', 'Inspected', 'Cancelled'],
}, },
vehiclenumber: {
type: DataTypes.TEXT,
},
phone: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
importHash: { importHash: {
type: DataTypes.STRING(255), type: DataTypes.STRING(255),
allowNull: true, allowNull: true,

View File

@ -22,6 +22,12 @@ const BookingsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
status: 'Inspected', status: 'Inspected',
vehiclenumber: 'Emil Kraepelin',
phone: 'Lynn Margulis',
email: 'Sigmund Freud',
}, },
{ {
@ -33,7 +39,13 @@ const BookingsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
status: 'Inspected', status: 'Pending',
vehiclenumber: 'Max Planck',
phone: 'Tycho Brahe',
email: 'Francis Galton',
}, },
{ {
@ -45,7 +57,13 @@ const BookingsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
status: 'Inspected', status: 'Cancelled',
vehiclenumber: 'Emil Fischer',
phone: 'Francis Crick',
email: 'Jean Baptiste Lamarck',
}, },
{ {
@ -57,19 +75,13 @@ const BookingsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
status: 'Cancelled',
},
{
title: 'Vehicle Inspection - William',
start_date: new Date('2023-11-05T11:00:00Z'),
end_date: new Date('2023-11-05T12:00:00Z'),
// type code here for "relation_one" field
status: 'Inspected', status: 'Inspected',
vehiclenumber: 'Nicolaus Copernicus',
phone: 'Charles Sherrington',
email: 'Ernest Rutherford',
}, },
]; ];
@ -89,10 +101,6 @@ const CategoriesData = [
{ {
name: 'Startup', name: 'Startup',
}, },
{
name: 'Non-Profit',
},
]; ];
const ContactsData = [ const ContactsData = [
@ -135,16 +143,6 @@ const ContactsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
}, },
{
first_name: 'Eve',
last_name: 'Adams',
email: 'eve.adams@example.com',
// type code here for "relation_one" field
},
]; ];
const DepartmentsData = [ const DepartmentsData = [
@ -171,19 +169,13 @@ const DepartmentsData = [
// type code here for "relation_many" field // type code here for "relation_many" field
}, },
{
name: 'IT',
// type code here for "relation_many" field
},
]; ];
const LeadsData = [ const LeadsData = [
{ {
name: 'Acme Corp', name: 'Acme Corp',
status: 'Qualified', status: 'Contacted',
// type code here for "relation_one" field // type code here for "relation_one" field
@ -193,7 +185,7 @@ const LeadsData = [
{ {
name: 'Beta LLC', name: 'Beta LLC',
status: 'Lost', status: 'Contacted',
// type code here for "relation_one" field // type code here for "relation_one" field
@ -203,7 +195,7 @@ const LeadsData = [
{ {
name: 'Gamma Inc', name: 'Gamma Inc',
status: 'Qualified', status: 'Contacted',
// type code here for "relation_one" field // type code here for "relation_one" field
@ -219,16 +211,6 @@ const LeadsData = [
// type code here for "relation_one" field // type code here for "relation_one" field
}, },
{
name: 'Epsilon Co',
status: 'Contacted',
// type code here for "relation_one" field
// type code here for "relation_one" field
},
]; ];
// Similar logic for "relation_many" // Similar logic for "relation_many"
@ -277,17 +259,6 @@ async function associateBookingWithUser() {
if (Booking3?.setUser) { if (Booking3?.setUser) {
await Booking3.setUser(relatedUser3); await Booking3.setUser(relatedUser3);
} }
const relatedUser4 = await Users.findOne({
offset: Math.floor(Math.random() * (await Users.count())),
});
const Booking4 = await Bookings.findOne({
order: [['id', 'ASC']],
offset: 4,
});
if (Booking4?.setUser) {
await Booking4.setUser(relatedUser4);
}
} }
async function associateContactWithOwner() { async function associateContactWithOwner() {
@ -334,17 +305,6 @@ async function associateContactWithOwner() {
if (Contact3?.setOwner) { if (Contact3?.setOwner) {
await Contact3.setOwner(relatedOwner3); await Contact3.setOwner(relatedOwner3);
} }
const relatedOwner4 = await Users.findOne({
offset: Math.floor(Math.random() * (await Users.count())),
});
const Contact4 = await Contacts.findOne({
order: [['id', 'ASC']],
offset: 4,
});
if (Contact4?.setOwner) {
await Contact4.setOwner(relatedOwner4);
}
} }
// Similar logic for "relation_many" // Similar logic for "relation_many"
@ -393,17 +353,6 @@ async function associateLeadWithOwner() {
if (Lead3?.setOwner) { if (Lead3?.setOwner) {
await Lead3.setOwner(relatedOwner3); await Lead3.setOwner(relatedOwner3);
} }
const relatedOwner4 = await Users.findOne({
offset: Math.floor(Math.random() * (await Users.count())),
});
const Lead4 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 4,
});
if (Lead4?.setOwner) {
await Lead4.setOwner(relatedOwner4);
}
} }
async function associateLeadWithCategory() { async function associateLeadWithCategory() {
@ -450,17 +399,6 @@ async function associateLeadWithCategory() {
if (Lead3?.setCategory) { if (Lead3?.setCategory) {
await Lead3.setCategory(relatedCategory3); await Lead3.setCategory(relatedCategory3);
} }
const relatedCategory4 = await Categories.findOne({
offset: Math.floor(Math.random() * (await Categories.count())),
});
const Lead4 = await Leads.findOne({
order: [['id', 'ASC']],
offset: 4,
});
if (Lead4?.setCategory) {
await Lead4.setCategory(relatedCategory4);
}
} }
module.exports = { module.exports = {

12
backend/src/holidays.js Normal file
View File

@ -0,0 +1,12 @@
// List of Fiji public holidays (YYYY-MM-DD)
module.exports = [
'2024-01-01', // New Year's Day
'2024-01-02', // Day after New Year's Day
'2024-04-14', // Good Friday
'2024-04-17', // Easter Monday
'2024-05-01', // Labour Day
'2024-10-10', // Fiji Day
'2024-12-25', // Christmas Day
'2024-12-26', // Boxing Day
// Add more dates as needed
];

View File

@ -8,6 +8,9 @@ const router = express.Router();
const { parse } = require('json2csv'); const { parse } = require('json2csv');
const moment = require('moment');
const holidays = require('../holidays');
const ValidationError = require('../services/notifications/errors/validation');
const { checkCrudPermissions } = require('../middlewares/check-permissions'); const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('bookings')); router.use(checkCrudPermissions('bookings'));
@ -23,6 +26,15 @@ router.use(checkCrudPermissions('bookings'));
* title: * title:
* type: string * type: string
* default: title * default: title
* vehiclenumber:
* type: string
* default: vehiclenumber
* phone:
* type: string
* default: phone
* email:
* type: string
* default: email
* *
*/ */
@ -73,6 +85,28 @@ router.post(
const referer = const referer =
req.headers.referer || req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`; `${req.protocol}://${req.hostname}${req.originalUrl}`;
// Booking validations
const { start_date, vehiclenumber, phone, email } = req.body.data;
if (!vehiclenumber) {
throw new ValidationError('vehicleNumberRequired', 'Vehicle number is required.');
}
if (!phone && !email) {
throw new ValidationError('contactInfoRequired', 'Either phone or email must be provided.');
}
const date = moment(start_date);
const day = date.day(); // Sunday = 0, Saturday = 6
const dateStr = date.format('YYYY-MM-DD');
if (day === 0) {
throw new ValidationError('noSundayBookings', 'Bookings cannot be made on Sundays.');
}
if (holidays.includes(dateStr)) {
throw new ValidationError('noHolidayBookings', 'Bookings cannot be made on public holidays.');
}
if (day === 6 && date.hour() > 13) {
throw new ValidationError('saturdayCutoff', 'Saturday bookings are only allowed until 1 PM.');
}
const link = new URL(referer); const link = new URL(referer);
await BookingsService.create( await BookingsService.create(
req.body.data, req.body.data,
@ -305,7 +339,16 @@ router.get(
const currentUser = req.currentUser; const currentUser = req.currentUser;
const payload = await BookingsDBApi.findAll(req.query, { currentUser }); const payload = await BookingsDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') { if (filetype && filetype === 'csv') {
const fields = ['id', 'title', 'start_date', 'end_date']; const fields = [
'id',
'title',
'vehiclenumber',
'phone',
'email',
'start_date',
'end_date',
];
const opts = { fields }; const opts = { fields };
try { try {
const csv = parse(payload.rows, opts); const csv = parse(payload.rows, opts);

View File

@ -43,7 +43,7 @@ module.exports = class SearchService {
const tableColumns = { const tableColumns = {
users: ['firstName', 'lastName', 'phoneNumber', 'email'], users: ['firstName', 'lastName', 'phoneNumber', 'email'],
bookings: ['title'], bookings: ['title', 'vehiclenumber', 'phone', 'email'],
categories: ['name'], categories: ['name'],

View File

@ -124,6 +124,31 @@ const CardBookings = ({
</div> </div>
</dd> </dd>
</div> </div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>
Vehiclenumber
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.vehiclenumber}
</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Phone</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>{item.phone}</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Email</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>{item.email}</div>
</dd>
</div>
</dl> </dl>
</li> </li>
))} ))}

View File

@ -81,6 +81,23 @@ const ListBookings = ({
<p className={'text-xs text-gray-500 '}>Status</p> <p className={'text-xs text-gray-500 '}>Status</p>
<p className={'line-clamp-2'}>{item.status}</p> <p className={'line-clamp-2'}>{item.status}</p>
</div> </div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>
Vehiclenumber
</p>
<p className={'line-clamp-2'}>{item.vehiclenumber}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Phone</p>
<p className={'line-clamp-2'}>{item.phone}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Email</p>
<p className={'line-clamp-2'}>{item.email}</p>
</div>
</Link> </Link>
<ListActionsPopover <ListActionsPopover
onDelete={onDelete} onDelete={onDelete}

View File

@ -114,6 +114,42 @@ export const loadColumns = async (
editable: hasUpdatePermission, editable: hasUpdatePermission,
}, },
{
field: 'vehiclenumber',
headerName: 'Vehiclenumber',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'phone',
headerName: 'Phone',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'email',
headerName: 'Email',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{ {
field: 'actions', field: 'actions',
type: 'actions', type: 'actions',

View File

@ -20,3 +20,15 @@ export const getPageTitle = (currentPageTitle: string) =>
`${currentPageTitle}${appTitle}`; `${currentPageTitle}${appTitle}`;
export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || ''; export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || '';
// Fiji public holidays (YYYY-MM-DD)
export const holidays: string[] = [
'2024-01-01', // New Year's Day
'2024-01-02', // Day after New Year's Day
'2024-04-14', // Good Friday
'2024-04-17', // Easter Monday
'2024-05-01', // Labour Day
'2024-10-10', // Fiji Day
'2024-12-25', // Christmas Day
'2024-12-26', // Boxing Day
];

View File

@ -45,6 +45,12 @@ const EditBookings = () => {
user: null, user: null,
status: '', status: '',
vehiclenumber: '',
phone: '',
email: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -160,6 +166,18 @@ const EditBookings = () => {
</Field> </Field>
</FormField> </FormField>
<FormField label='Vehiclenumber'>
<Field name='vehiclenumber' placeholder='Vehiclenumber' />
</FormField>
<FormField label='Phone'>
<Field name='phone' placeholder='Phone' />
</FormField>
<FormField label='Email'>
<Field name='email' placeholder='Email' />
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -45,6 +45,12 @@ const EditBookingsPage = () => {
user: null, user: null,
status: '', status: '',
vehiclenumber: '',
phone: '',
email: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -158,6 +164,18 @@ const EditBookingsPage = () => {
</Field> </Field>
</FormField> </FormField>
<FormField label='Vehiclenumber'>
<Field name='vehiclenumber' placeholder='Vehiclenumber' />
</FormField>
<FormField label='Phone'>
<Field name='phone' placeholder='Phone' />
</FormField>
<FormField label='Email'>
<Field name='email' placeholder='Email' />
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -30,6 +30,9 @@ const BookingsTablesPage = () => {
const [filters] = useState([ const [filters] = useState([
{ label: 'Title', title: 'title' }, { label: 'Title', title: 'title' },
{ label: 'Vehiclenumber', title: 'vehiclenumber' },
{ label: 'Phone', title: 'phone' },
{ label: 'Email', title: 'email' },
{ label: 'StartDate', title: 'start_date', date: 'true' }, { label: 'StartDate', title: 'start_date', date: 'true' },
{ label: 'EndDate', title: 'end_date', date: 'true' }, { label: 'EndDate', title: 'end_date', date: 'true' },

View File

@ -4,9 +4,11 @@ import {
mdiMail, mdiMail,
mdiUpload, mdiUpload,
} from '@mdi/js'; } from '@mdi/js';
import { holidays } from '../../config';
import Head from 'next/head'; import Head from 'next/head';
import React, { ReactElement } from 'react'; import React, { ReactElement } from 'react';
import CardBox from '../../components/CardBox'; import CardBox from '../../components/CardBox';
import LayoutGuest from '../../layouts/Guest';
import LayoutAuthenticated from '../../layouts/Authenticated'; import LayoutAuthenticated from '../../layouts/Authenticated';
import SectionMain from '../../components/SectionMain'; import SectionMain from '../../components/SectionMain';
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'; import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
@ -33,15 +35,11 @@ import { useRouter } from 'next/router';
import moment from 'moment'; import moment from 'moment';
const initialValues = { const initialValues = {
title: '', date: '',
timeSlot: '',
start_date: '', vehiclenumber: '',
phone: '',
end_date: '', email: '',
user: '',
status: 'Pending',
}; };
const BookingsNew = () => { const BookingsNew = () => {
@ -69,73 +67,65 @@ const BookingsNew = () => {
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
<Formik <Formik initialValues={initialValues} onSubmit={handleSubmit}>
initialValues={ {({ values }) => {
dateRangeStart && dateRangeEnd // Generate 20-minute slots between 08:00 and 16:00
? { const slots: string[] = [];
...initialValues, if (values.date) {
start_date: const date = moment(values.date);
moment(dateRangeStart).format('YYYY-MM-DDTHH:mm'), const day = date.day(); // Sunday = 0, Saturday = 6
end_date: moment(dateRangeEnd).format('YYYY-MM-DDTHH:mm'), const dateStr = date.format('YYYY-MM-DD');
const startHour = 8;
const endHour = 16;
let cursor = date.clone().hour(startHour).minute(0);
while (cursor.hour() < endHour) {
const slot = cursor.format('HH:mm');
// Exclude Sundays and holidays
if (day !== 0 && !holidays.includes(dateStr)) {
// Saturday cutoff at 13:00
if (!(day === 6 && cursor.hour() > 13)) {
slots.push(slot);
}
} }
: initialValues cursor = cursor.add(20, 'minutes');
} }
onSubmit={(values) => handleSubmit(values)} }
> return (
<Form> <Form>
<FormField label='Title'> <FormField label="Date">
<Field name='title' placeholder='Title' /> <Field type="date" name="date" />
</FormField> </FormField>
<FormField label="Time Slot">
<FormField label='StartDate'> <Field
<Field component={SelectField}
type='datetime-local' name="timeSlot"
name='start_date' options={slots.map((s) => ({ label: s, value: s }))}
placeholder='StartDate' />
/> </FormField>
</FormField> <FormField label="Vehicle Number">
<Field name="vehiclenumber" placeholder="Vehicle Number" />
<FormField label='EndDate'> </FormField>
<Field <FormField label="Phone">
type='datetime-local' <Field name="phone" placeholder="Your phone" />
name='end_date' </FormField>
placeholder='EndDate' <FormField label="Email">
/> <Field name="email" placeholder="Your email" />
</FormField> </FormField>
<BaseDivider />
<FormField label='User' labelFor='user'> <BaseButtons>
<Field <BaseButton type="submit" color="info" label="Submit" />
name='user' <BaseButton type="reset" color="info" outline label="Reset" />
id='user' <BaseButton
component={SelectField} type="button"
options={[]} color="danger"
itemRef={'users'} outline
></Field> label="Cancel"
</FormField> onClick={() => router.push('/')}
/>
<FormField label='Status' labelFor='status'> </BaseButtons>
<Field name='status' id='status' component='select'> </Form>
<option value='Pending'>Pending</option> );
}}
<option value='Inspected'>Inspected</option>
<option value='Cancelled'>Cancelled</option>
</Field>
</FormField>
<BaseDivider />
<BaseButtons>
<BaseButton type='submit' color='info' label='Submit' />
<BaseButton type='reset' color='info' outline label='Reset' />
<BaseButton
type='reset'
color='danger'
outline
label='Cancel'
onClick={() => router.push('/bookings/bookings-list')}
/>
</BaseButtons>
</Form>
</Formik> </Formik>
</CardBox> </CardBox>
</SectionMain> </SectionMain>
@ -145,9 +135,9 @@ const BookingsNew = () => {
BookingsNew.getLayout = function getLayout(page: ReactElement) { BookingsNew.getLayout = function getLayout(page: ReactElement) {
return ( return (
<LayoutAuthenticated permission={'CREATE_BOOKINGS'}> <LayoutGuest>
{page} {page}
</LayoutAuthenticated> </LayoutGuest>
); );
}; };

View File

@ -30,6 +30,9 @@ const BookingsTablesPage = () => {
const [filters] = useState([ const [filters] = useState([
{ label: 'Title', title: 'title' }, { label: 'Title', title: 'title' },
{ label: 'Vehiclenumber', title: 'vehiclenumber' },
{ label: 'Phone', title: 'phone' },
{ label: 'Email', title: 'email' },
{ label: 'StartDate', title: 'start_date', date: 'true' }, { label: 'StartDate', title: 'start_date', date: 'true' },
{ label: 'EndDate', title: 'end_date', date: 'true' }, { label: 'EndDate', title: 'end_date', date: 'true' },

View File

@ -108,6 +108,21 @@ const BookingsView = () => {
<p>{bookings?.status ?? 'No data'}</p> <p>{bookings?.status ?? 'No data'}</p>
</div> </div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Vehiclenumber</p>
<p>{bookings?.vehiclenumber}</p>
</div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Phone</p>
<p>{bookings?.phone}</p>
</div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Email</p>
<p>{bookings?.email}</p>
</div>
<BaseDivider /> <BaseDivider />
<BaseButton <BaseButton

View File

@ -96,7 +96,7 @@ export default function WebSite() {
<FeaturesSection <FeaturesSection
projectName={'Vehicle Inspection Booking System'} projectName={'Vehicle Inspection Booking System'}
image={['Dashboard showcasing CRM features']} image={['Dashboard showcasing CRM features']}
withBg={1} withBg={0}
features={features_points} features={features_points}
mainText={`Discover Key Features of ${projectName}`} mainText={`Discover Key Features of ${projectName}`}
subTitle={`Unlock the full potential of your legal operations with ${projectName}. Streamline processes, enhance collaboration, and boost productivity.`} subTitle={`Unlock the full potential of your legal operations with ${projectName}. Streamline processes, enhance collaboration, and boost productivity.`}

View File

@ -155,6 +155,12 @@ const UsersView = () => {
<th>EndDate</th> <th>EndDate</th>
<th>Status</th> <th>Status</th>
<th>Vehiclenumber</th>
<th>Phone</th>
<th>Email</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -180,6 +186,14 @@ const UsersView = () => {
</td> </td>
<td data-label='status'>{item.status}</td> <td data-label='status'>{item.status}</td>
<td data-label='vehiclenumber'>
{item.vehiclenumber}
</td>
<td data-label='phone'>{item.phone}</td>
<td data-label='email'>{item.email}</td>
</tr> </tr>
))} ))}
</tbody> </tbody>

View File

@ -110,7 +110,7 @@ export default function WebSite() {
<FeaturesSection <FeaturesSection
projectName={'Vehicle Inspection Booking System'} projectName={'Vehicle Inspection Booking System'}
image={['Icons representing CRM features']} image={['Icons representing CRM features']}
withBg={1} withBg={0}
features={features_points} features={features_points}
mainText={`Unleash the Power of ${projectName}`} mainText={`Unleash the Power of ${projectName}`}
subTitle={`Explore the robust features of ${projectName} designed to elevate your legal practice. Enhance productivity, streamline operations, and drive success.`} subTitle={`Explore the robust features of ${projectName} designed to elevate your legal practice. Enhance productivity, streamline operations, and drive success.`}