305 lines
12 KiB
TypeScript
305 lines
12 KiB
TypeScript
import {
|
||
mdiAccountCashOutline,
|
||
mdiCashRegister,
|
||
mdiClipboardCheckOutline,
|
||
mdiClipboardListOutline,
|
||
mdiCogOutline,
|
||
mdiHelpCircleOutline,
|
||
mdiOpenInNew,
|
||
mdiPlayCircleOutline,
|
||
mdiShieldCheckOutline,
|
||
} from '@mdi/js';
|
||
import Head from 'next/head';
|
||
import React, { ReactElement } from 'react';
|
||
|
||
import BaseButton from '../components/BaseButton';
|
||
import BaseDivider from '../components/BaseDivider';
|
||
import BaseIcon from '../components/BaseIcon';
|
||
import CardBox from '../components/CardBox';
|
||
import SectionMain from '../components/SectionMain';
|
||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
|
||
import { getPageTitle } from '../config';
|
||
import LayoutAuthenticated from '../layouts/Authenticated';
|
||
|
||
type HelpSection = {
|
||
id: string;
|
||
title: string;
|
||
icon: string;
|
||
summary: string;
|
||
steps: string[];
|
||
checks?: string[];
|
||
warning?: string;
|
||
href?: string;
|
||
hrefLabel?: string;
|
||
};
|
||
|
||
const helpSections: HelpSection[] = [
|
||
{
|
||
id: 'getting-started',
|
||
title: 'Getting started',
|
||
icon: mdiPlayCircleOutline,
|
||
summary:
|
||
'Use this as the admin’s quick-start routine before you begin assigning pay or creating payroll runs.',
|
||
steps: [
|
||
'Confirm your users, customers, vehicles, pay types, and workers comp classes are up to date.',
|
||
'Make sure employees know whether they should use Log Work or whether an admin is entering logs on their behalf.',
|
||
'Decide how often payroll should be run and which date range each payroll run should cover.',
|
||
'Review this help page the first few times so your workflow stays consistent.',
|
||
],
|
||
checks: [
|
||
'Users have the correct role and active account status.',
|
||
'Employees have at least one pay setup assigned before they start logging jobs.',
|
||
'Admins know which menu pages they will use most often: Users, Pay types, Employee pay types, All Job Logs, and Payroll runs.',
|
||
],
|
||
href: '/dashboard',
|
||
hrefLabel: 'Open Dashboard',
|
||
},
|
||
{
|
||
id: 'assign-employee-pay',
|
||
title: 'Assign employee pay',
|
||
icon: mdiAccountCashOutline,
|
||
summary:
|
||
'This links an employee to the pay option they are allowed to use on jobs.',
|
||
steps: [
|
||
'Open Employee pay types.',
|
||
'Create a new record and select the employee.',
|
||
'Choose the pay type you want that employee to use, such as hourly or commission.',
|
||
'Save the record and verify the employee can now select that pay option while logging work.',
|
||
'If an employee should have multiple valid pay options, add each allowed pay type as its own assignment.',
|
||
],
|
||
checks: [
|
||
'Use clear pay type names so employees can easily choose the right option while logging work.',
|
||
'Remove outdated assignments if an employee should no longer use an old rate or method.',
|
||
],
|
||
href: '/employee_pay_types/employee_pay_types-list',
|
||
hrefLabel: 'Open Employee Pay Types',
|
||
},
|
||
{
|
||
id: 'set-up-pay-types',
|
||
title: 'Set up pay types',
|
||
icon: mdiCogOutline,
|
||
summary:
|
||
'Pay types control how job pay is calculated. Keep these clean and intentional so payroll stays predictable.',
|
||
steps: [
|
||
'Open Pay types and review the existing list before adding a new one.',
|
||
'For hourly work, confirm the hourly rate is correct.',
|
||
'For commission-based work, confirm the commission percentage is correct.',
|
||
'Use consistent naming so admins and employees can tell similar pay types apart.',
|
||
'Save changes, then test a sample job log if the pay logic is new or changed.',
|
||
],
|
||
checks: [
|
||
'Avoid creating duplicate pay types with only slightly different names.',
|
||
'When changing a rate, double-check whether you should edit an existing pay type or create a new one for future use.',
|
||
],
|
||
href: '/pay_types/pay_types-list',
|
||
hrefLabel: 'Open Pay Types',
|
||
},
|
||
{
|
||
id: 'review-job-logs',
|
||
title: 'Review job logs before payroll',
|
||
icon: mdiClipboardCheckOutline,
|
||
summary:
|
||
'A quick review before payroll helps catch missing hours, wrong pay types, or incomplete client-paid amounts.',
|
||
steps: [
|
||
'Open All Job Logs and filter by the payroll period you are about to run.',
|
||
'Scan Employee Pay, hours, client paid, and pay type selections for anything that looks incorrect.',
|
||
'Open any questionable record and verify the employee, customer, vehicle, and work details.',
|
||
'Fix missing or incorrect values before creating the payroll run.',
|
||
],
|
||
checks: [
|
||
'Hourly jobs should have hours entered.',
|
||
'Commission jobs should have the client paid amount entered.',
|
||
'Employees should not have duplicate or accidental logs for the same work.',
|
||
],
|
||
href: '/job_logs/job_logs-list',
|
||
hrefLabel: 'Open All Job Logs',
|
||
},
|
||
{
|
||
id: 'run-payroll',
|
||
title: 'Run payroll',
|
||
icon: mdiCashRegister,
|
||
summary:
|
||
'Create a payroll run only after the logs in that date range look clean.',
|
||
steps: [
|
||
'Open Payroll runs and create a new run.',
|
||
'Set the payroll dates carefully so the run only includes the jobs you intend to pay.',
|
||
'Save the payroll run and review the generated results.',
|
||
'Open the payroll line items if you need job-by-job detail for what was included.',
|
||
'If totals look wrong, go back to the source job logs, correct them, and then rerun or recreate payroll as needed.',
|
||
],
|
||
checks: [
|
||
'Watch for an incorrect date range first; that is one of the most common causes of missing or extra pay.',
|
||
'If one employee total looks off, inspect that employee’s individual job logs before changing anything else.',
|
||
],
|
||
href: '/payroll_runs/payroll_runs-list',
|
||
hrefLabel: 'Open Payroll Runs',
|
||
},
|
||
{
|
||
id: 'check-results',
|
||
title: 'Check payroll results',
|
||
icon: mdiClipboardListOutline,
|
||
summary:
|
||
'After a run is created, verify the output before treating it as final.',
|
||
steps: [
|
||
'Review the payroll run totals and compare them with the expected workload for that period.',
|
||
'Open Payroll line items to confirm each employee has the right combination of job entries.',
|
||
'Spot-check a few records manually using the job log Employee Pay values and the live preview logic on the log form.',
|
||
'Use the Payroll Dashboard if you want a broader visual review of payroll activity.',
|
||
],
|
||
checks: [
|
||
'Investigate unusual spikes or drops before approving the numbers internally.',
|
||
'Keep a repeatable review routine so payroll checks stay consistent every pay period.',
|
||
],
|
||
href: '/reports',
|
||
hrefLabel: 'Open Payroll Dashboard',
|
||
},
|
||
{
|
||
id: 'troubleshooting',
|
||
title: 'Troubleshooting and common issues',
|
||
icon: mdiShieldCheckOutline,
|
||
summary:
|
||
'Use this checklist whenever the numbers do not look right or an employee cannot complete a job log correctly.',
|
||
steps: [
|
||
'If an employee cannot choose the right pay option, confirm the Employee pay types assignment exists.',
|
||
'If live pay looks wrong on a job log, verify the pay type values and the job fields used for that method.',
|
||
'If payroll totals look off, compare the payroll date range with the dates on the job logs included in the run.',
|
||
'If a commission total looks too low or too high, check the client paid amount on the job log first.',
|
||
'If an hourly total looks wrong, check hours entered and the selected hourly pay type.',
|
||
],
|
||
warning:
|
||
'Best practice: fix the source job log or pay setup first, then regenerate or recreate the payroll output instead of trying to explain away a mismatch later.',
|
||
href: '/payroll_line_items/payroll_line_items-list',
|
||
hrefLabel: 'Open Payroll Line Items',
|
||
},
|
||
];
|
||
|
||
const AdminHelpPage = () => {
|
||
return (
|
||
<>
|
||
<Head>
|
||
<title>{getPageTitle('Admin Help')}</title>
|
||
</Head>
|
||
|
||
<SectionMain>
|
||
<SectionTitleLineWithButton
|
||
icon={mdiHelpCircleOutline}
|
||
title='Admin Help'
|
||
main
|
||
>
|
||
{''}
|
||
</SectionTitleLineWithButton>
|
||
|
||
<CardBox className='mb-6'>
|
||
<div className='flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between'>
|
||
<div className='max-w-3xl'>
|
||
<h2 className='text-xl font-semibold mb-2'>Admin task checklist</h2>
|
||
<p className='text-gray-600 dark:text-gray-300'>
|
||
This page is a simple internal knowledge base for the most common admin workflows in the app.
|
||
Use the quick links below to jump to a process, then open the related page directly when you are ready to do the task.
|
||
</p>
|
||
</div>
|
||
<BaseButton
|
||
href='/payroll_runs/payroll_runs-list'
|
||
color='info'
|
||
icon={mdiOpenInNew}
|
||
label='Go to Payroll Runs'
|
||
/>
|
||
</div>
|
||
|
||
<BaseDivider />
|
||
|
||
<div className='flex flex-wrap gap-3'>
|
||
{helpSections.map((section) => (
|
||
<BaseButton
|
||
key={section.id}
|
||
asAnchor
|
||
href={`#${section.id}`}
|
||
color='whiteDark'
|
||
small
|
||
label={section.title}
|
||
/>
|
||
))}
|
||
</div>
|
||
</CardBox>
|
||
|
||
<div className='grid grid-cols-1 gap-6 xl:grid-cols-2'>
|
||
{helpSections.map((section) => (
|
||
<CardBox key={section.id} className='h-full'>
|
||
<div id={section.id} className='scroll-mt-20'>
|
||
<div className='flex items-start justify-between gap-4 mb-4'>
|
||
<div className='flex items-start gap-3'>
|
||
<BaseIcon path={section.icon} size={28} className='text-blue-600 dark:text-blue-400 mt-1' />
|
||
<div>
|
||
<h2 className='text-xl font-semibold'>{section.title}</h2>
|
||
<p className='text-sm text-gray-600 dark:text-gray-300 mt-1'>
|
||
{section.summary}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
{section.href && section.hrefLabel ? (
|
||
<BaseButton
|
||
href={section.href}
|
||
color='info'
|
||
small
|
||
icon={mdiOpenInNew}
|
||
label={section.hrefLabel}
|
||
/>
|
||
) : null}
|
||
</div>
|
||
|
||
<div className='mb-4'>
|
||
<div className='text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400 mb-2'>
|
||
Checklist
|
||
</div>
|
||
<ol className='list-decimal pl-5 space-y-2 text-sm leading-6'>
|
||
{section.steps.map((step) => (
|
||
<li key={step}>{step}</li>
|
||
))}
|
||
</ol>
|
||
</div>
|
||
|
||
{section.checks?.length ? (
|
||
<div className='mb-4'>
|
||
<div className='text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400 mb-2'>
|
||
Verify before moving on
|
||
</div>
|
||
<ul className='list-disc pl-5 space-y-2 text-sm leading-6'>
|
||
{section.checks.map((check) => (
|
||
<li key={check}>{check}</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
) : null}
|
||
|
||
{section.warning ? (
|
||
<div className='rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm leading-6 text-amber-900 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-100'>
|
||
<span className='font-semibold'>Admin note:</span> {section.warning}
|
||
</div>
|
||
) : null}
|
||
</div>
|
||
</CardBox>
|
||
))}
|
||
</div>
|
||
|
||
<CardBox className='mt-6'>
|
||
<div className='flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between'>
|
||
<div>
|
||
<h2 className='text-lg font-semibold'>Suggested next improvement</h2>
|
||
<p className='text-sm text-gray-600 dark:text-gray-300 mt-1'>
|
||
If you want, this help page can later become searchable or editable so admins can maintain their own internal SOPs.
|
||
</p>
|
||
</div>
|
||
<BaseButton href='/dashboard' color='whiteDark' label='Back to Dashboard' />
|
||
</div>
|
||
</CardBox>
|
||
</SectionMain>
|
||
</>
|
||
);
|
||
};
|
||
|
||
AdminHelpPage.getLayout = function getLayout(page: ReactElement) {
|
||
return <LayoutAuthenticated permission='UPDATE_USERS'>{page}</LayoutAuthenticated>;
|
||
};
|
||
|
||
export default AdminHelpPage;
|