This commit is contained in:
Dave Richer
2023-12-11 17:34:05 -05:00
parent 5c164f807d
commit ad79344709
87 changed files with 1100 additions and 1113 deletions

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import BillDeleteButton from "../../components/bill-delete-button/bill-delete-button.component";
import PartsOrderModalContainer from "../../components/parts-order-modal/parts-order-modal.container";
import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.component";
@@ -31,7 +31,7 @@ export function BillsListPage({
setPartsOrderContext,
setBillEnterContext,
}) {
const search = queryString.parse(useLocation().search);
const search = queryString.parse(useSearchParams().toString());
const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false);
const { page } = search;
@@ -212,7 +212,7 @@ export function BillsListPage({
search.sortorder = sorter.order;
}
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
history.push({ search: queryString.stringify(search) });
history({ search: queryString.stringify(search) });
};
useEffect(() => {
@@ -251,7 +251,7 @@ export function BillsListPage({
onClick={() => {
delete search.search;
delete search.page;
history.push({ search: queryString.stringify(search) });
history({ search: queryString.stringify(search) });
}}
>
{t("general.actions.clear")}
@@ -276,7 +276,7 @@ export function BillsListPage({
placeholder={search.search || t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
history({ search: queryString.stringify(search) });
searchBills(value);
}}
loading={loading || searchLoading}

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component";
import BillDetailEditContainer from "../../components/bill-detail-edit/bill-detail-edit.container";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
@@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, searchObj } = searchParams;
useEffect(() => {

View File

@@ -3,7 +3,7 @@ import { Form, notification } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import { useSearchParams, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries";
@@ -31,11 +31,11 @@ export function ContractCreatePageContainer({
const [form] = Form.useForm();
const { t } = useTranslation();
const history = useNavigate();
const location = useLocation();
const searchParams = useSearchParams();
const [loading, setLoading] = useState(false);
const selectedCarState = useState(null);
const selectedJobState = useState(
(location.state && location.state.jobId) || null
(searchParams.get('state') && searchParams.get('state').jobId) || null
);
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
const [intakeJob] = useMutation(UPDATE_JOB);
@@ -87,7 +87,7 @@ export function ContractCreatePageContainer({
form.resetFields();
form.resetFields();
history.push(
history(
`/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}`
);
} else {

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_ACTIVE_CONTRACTS_PAGINATED } from "../../graphql/cccontracts.queries";
@@ -20,7 +20,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function ContractsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { search, page, sortcolumn, sortorder } = searchParams;
const { loading, error, data, refetch } = useQuery(

View File

@@ -50,7 +50,7 @@ export function CourtesyCarCreateContainer({
form.resetFields();
form.resetFields();
notification["success"]({ message: t("courtesycars.successes.saved") });
history.push(
history(
`/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}`
);
}

View File

@@ -18,7 +18,7 @@ import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component
import NotFound from "../../components/not-found/not-found.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import queryString from "query-string";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import {pageLimit} from "../../utils/config";
const mapDispatchToProps = (dispatch) => ({
@@ -31,7 +31,7 @@ export function CourtesyCarDetailPageContainer({
addRecentItem,
setSelectedHeader,
}) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder } = searchParams;
const { t } = useTranslation();

View File

@@ -2,7 +2,7 @@ import { Button, Card, Col, notification, Row, Select, Space } from "antd";
import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import SocketIO from "socket.io-client";
import DmsAllocationsSummaryApComponent from "../../components/dms-allocations-summary-ap/dms-allocations-summary-ap.component";
@@ -45,9 +45,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const history = useNavigate();
const [logs, setLogs] = useState([]);
const { state } = useLocation();
const logsRef = useRef(null);
const searchParams = useSearchParams();
const state = Object.fromEntries(searchParams);
const logsRef = useRef(null);
useEffect(() => {
document.title = t("titles.dms");
@@ -101,7 +101,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
}, []);
if (!state?.billids) {
history.push(`/manage/accounting/payables`);
history(`/manage/accounting/payables`);
}
return (

View File

@@ -13,7 +13,7 @@ import queryString from "query-string";
import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import SocketIO from "socket.io-client";
import AlertComponent from "../../components/alert/alert.component";
@@ -62,7 +62,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const [logLevel, setLogLevel] = useState("DEBUG");
const history = useNavigate();
const [logs, setLogs] = useState([]);
const search = queryString.parse(useLocation().search);
const search = queryString.parse(useSearchParams().toString());
const { jobId } = search;
const { loading, error, data } = useQuery(QUERY_JOB_EXPORT_DMS, {
@@ -115,7 +115,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
notification.success({
message: t("jobs.successes.exported"),
});
history.push("/manage/accounting/receivables");
history("/manage/accounting/receivables");
});
if (socket.disconnected) socket.connect();

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
@@ -19,7 +19,7 @@ const mapStateToProps = createStructuredSelector({
});
export function ExportLogsPageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search } = searchParams;
const history = useNavigate();
@@ -60,7 +60,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
} else {
delete searchParams.statusFilters;
}
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
};
const columns = [
@@ -155,7 +155,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
<Button
onClick={() => {
delete searchParams.search;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
}}
>
{t("general.actions.clear")}
@@ -169,7 +169,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
placeholder={searchParams.search || t("general.labels.search")}
onSearch={(value) => {
searchParams.search = value;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
}}
/>
</Space>

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import JobsListPaginated from "../../components/jobs-list-paginated/jobs-list-paginated.component";
@@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, statusFilters } = searchParams;
const { loading, error, data, refetch } = useQuery(

View File

@@ -21,7 +21,7 @@ import {
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
//import { useHistory } from "react-router-dom";
// import { useNavigate } from 'react-router-dom';
import { useTreatments } from "@splitsoftware/splitio-react";
import Dinero from "dinero.js";
import moment from "moment";
@@ -110,7 +110,9 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
notification["success"]({
message: t("jobs.successes.closed"),
});
// history.push(`/manage/jobs/${job.id}`);
// const navigate = useNavigate();
// navigate(`/manage/jobs/${job.id}`);
} else {
setLoading(false);
notification["error"]({

View File

@@ -24,7 +24,7 @@ import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux";
import {useNavigate, useLocation} from "react-router-dom";
import {useNavigate, useSearchParams} from "react-router-dom";
import { createStructuredSelector } from "reselect";
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
@@ -79,8 +79,7 @@ export function JobsDetailPage({
const [form] = Form.useForm();
const history = useNavigate();
const [loading, setLoading] = useState(false);
const search = queryString.parse(useLocation().search);
const search = queryString.parse(useSearchParams().toString());
const formItemLayout = {
layout: "vertical",
};
@@ -256,7 +255,7 @@ export function JobsDetailPage({
<FormFieldsChanged form={form} />
<Tabs
defaultActiveKey={search.tab}
onChange={(key) => history.push({ search: `?tab=${key}` })}
onChange={(key) => history({ search: `?tab=${key}` })}
tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }}
>
<Tabs.TabPane

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, {useEffect} from "react";
import { connect } from "react-redux";
import { useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
@@ -13,8 +13,12 @@ export default connect(mapStateToProps, null)(LandingPage);
export function LandingPage({ currentUser }) {
const navigate = useNavigate();
if (currentUser.authorized) return navigate("/manage");
return <LandingPageStatic />;
//return <Redirect to={"/signin"} />;
useEffect(() => {
if (!currentUser.authorized) {
navigate('/manage');
}
}, [currentUser, navigate]);
return currentUser.authorized ? <LandingPageStatic /> : <div />;
}

View File

@@ -1,14 +1,19 @@
import React from "react";
import React, {useEffect} from "react";
//import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
import { useNavigate } from "react-router-dom";
export default function ManageRootPageComponent() {
//const client = useApolloClient();
const navigate = useNavigate();
return navigate("/manage/jobs");
useEffect(() => {
navigate('/manage/jobs');
}, [navigate]);
return <div />;
// return (
// <div>
// <DashboardGridComponent />
// </div>
// );
}

View File

@@ -179,7 +179,13 @@ const mapStateToProps = createStructuredSelector({
});
export function Manage({ match, conflict, bodyshop }) {
// TODO: Remove after client upgrade
console.log('Manage Page :');
console.dir({ match, conflict, bodyshop });
const { t } = useTranslation();
useEffect(() => {
const widgetId = "IABVNO4scRKY11XBQkNr";
window.noticeable.render("widget", widgetId);
@@ -209,184 +215,152 @@ export function Manage({ match, conflict, bodyshop }) {
<EmailOverlayContainer />
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<Route exact path={`${match.path}/_test`} component={TestComponent} />
<Route exact path={`${match.path}`} component={ManageRootPage} />
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
<Route path={`${match.path}/_test`} element={<TestComponent />} />
<Route path={`${match.path}`} element={<ManageRootPage />} />
<Route path={`${match.path}/jobs`} element={<JobsPage />} />
<Routes>
<Route
exact
path={`${match.path}/jobs/:jobId/intake`}
component={JobIntake}
element={<JobIntake />}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/deliver`}
component={JobDeliver}
element={<JobDeliver />}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/checklist`}
component={JobChecklistView}
element={<JobChecklistView />}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/close`}
component={JobsClose}
element={<JobsClose />}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/admin`}
component={JobsAdmin}
element={<JobsAdmin />}
/>
<Route exact path={`${match.path}/jobs/all`} component={AllJobs} />
<Route exact path={`${match.path}/jobs/ready`} component={ReadyJobs} />
<Route path={`${match.path}/jobs/all`} element={<AllJobs />} />
<Route path={`${match.path}/jobs/ready`} element={<ReadyJobs />} />
<Route
exact
path={`${match.path}/jobs/new`}
component={JobsCreateContainerPage}
element={<JobsCreateContainerPage />}
/>
<Route path={`${match.path}/jobs/:jobId`} component={JobsDetailPage} />
<Route path={`${match.path}/jobs/:jobId`} element={<JobsDetailPage />} />
</Routes>
<Route exact path={`${match.path}/temporarydocs/`} component={TempDocs} />
<Route path={`${match.path}/temporarydocs/`} element={<TempDocs />} />
<Route
exact
path={`${match.path}/inventory/`}
component={InventoryListPage}
element={<InventoryListPage />}
/>
<Route
exact
path={`${match.path}/courtesycars/`}
component={CourtesyCarsPage}
element={<CourtesyCarsPage />}
/>
<Routes>
<Route
exact
path={`${match.path}/courtesycars/new`}
component={CourtesyCarCreateContainer}
element={<CourtesyCarCreateContainer />}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts`}
component={ContractsList}
element={<ContractsList />}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts/new`}
component={ContractCreatePage}
element={<ContractCreatePage />}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts/:contractId`}
component={ContractDetailPage}
element={<ContractDetailPage />}
/>
<Route
exact
path={`${match.path}/courtesycars/:ccId`}
component={CourtesyCarDetailContainer}
element={<CourtesyCarDetailContainer />}
/>
</Routes>
<Route exact path={`${match.path}/profile`} component={ProfilePage} />
<Route path={`${match.path}/profile`} element={<ProfilePage />} />
<Route
exact
path={`${match.path}/vehicles`}
component={VehiclesContainer}
element={<VehiclesContainer />}
/>
<Route
exact
path={`${match.path}/production/list`}
component={ProductionListPage}
element={<ProductionListPage />}
/>
<Route
exact
path={`${match.path}/production/board`}
component={ProductionBoardPage}
element={<ProductionBoardPage />}
/>
<Route
exact
path={`${match.path}/vehicles/:vehId`}
component={VehiclesDetailContainer}
element={<VehiclesDetailContainer />}
/>
<Route exact path={`${match.path}/bills`} component={BillsListPage} />
<Route exact path={`${match.path}/owners`} component={OwnersContainer} />
<Route path={`${match.path}/bills`} element={<BillsListPage />} />
<Route path={`${match.path}/owners`} element={<OwnersContainer />} />
<Route
exact
path={`${match.path}/owners/:ownerId`}
component={OwnersDetailContainer}
element={<OwnersDetailContainer />}
/>
<Route
exact
path={`${match.path}/schedule`}
component={ScheduleContainer}
element={<ScheduleContainer />}
/>
<Route
exact
path={`${match.path}/available`}
component={JobsAvailablePage}
element={<JobsAvailablePage />}
/>
<Route exact path={`${match.path}/shop/`} component={ShopPage} />
<Route path={`${match.path}/shop/`} element={<ShopPage />} />
{
// <Route
// exact
// path={`${match.path}/shop/templates`}
// component={ShopTemplates}
// element={<ShopTemplates />}
// />
}
<Route
exact
path={`${match.path}/shop/vendors`}
component={ShopVendorPageContainer}
element={<ShopVendorPageContainer />}
/>
<Route
exact
path={`${match.path}/shop/csi`}
component={ShopCsiPageContainer}
element={<ShopCsiPageContainer />}
/>
<Route
exact
path={`${match.path}/accounting/qbo`}
component={AccountingQboCallback}
element={<AccountingQboCallback />}
/>
<Route
exact
path={`${match.path}/accounting/receivables`}
component={AccountingReceivables}
element={<AccountingReceivables />}
/>
<Route
exact
path={`${match.path}/accounting/payables`}
component={AccountingPayables}
element={<AccountingPayables />}
/>
<Route
exact
path={`${match.path}/accounting/payments`}
component={AccountingPayments}
element={<AccountingPayments />}
/>
<Route
exact
path={`${match.path}/accounting/exportlogs`}
component={ExportLogs}
element={<ExportLogs />}
/>
<Route exact path={`${match.path}/partsqueue`} component={PartsQueue} />
<Route exact path={`${match.path}/phonebook`} component={Phonebook} />
<Route path={`${match.path}/partsqueue`} element={<PartsQueue />} />
<Route path={`${match.path}/phonebook`} element={<Phonebook />} />
<Route exact path={`${match.path}/payments`} component={PaymentsAll} />
<Route exact path={`${match.path}/shiftclock`} component={ShiftClock} />
<Route exact path={`${match.path}/scoreboard`} component={Scoreboard} />
<Route path={`${match.path}/payments`} element={<PaymentsAll />} />
<Route path={`${match.path}/shiftclock`} element={<ShiftClock />} />
<Route path={`${match.path}/scoreboard`} element={<Scoreboard />} />
<Route
exact
path={`${match.path}/timetickets`}
component={TimeTicketsAll}
element={<TimeTicketsAll />}
/>
<Route exact path={`${match.path}/help`} component={Help} />
<Route exact path={`${match.path}/emailtest`} component={EmailTest} />
<Route exact path={`${match.path}/dashboard`} component={Dashboard} />
<Route exact path={`${match.path}/dms`} component={Dms} />
<Route exact path={`${match.path}/dmsap`} component={DmsPayables} />
<Route path={`${match.path}/help`} element={<Help />} />
<Route path={`${match.path}/emailtest`} element={<EmailTest />} />
<Route path={`${match.path}/dashboard`} element={<Dashboard />} />
<Route path={`${match.path}/dms`} element={<Dms />} />
<Route path={`${match.path}/dmsap`} element={<DmsPayables />} />
</Suspense>
);

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
@@ -25,7 +25,7 @@ const mapStateToProps = createStructuredSelector({
});
export function PartsQueuePageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const {
//page,
sortcolumn,
@@ -104,7 +104,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
delete searchParams.statusFilters;
}
setFilter(filters);
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
};
const columns = [

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import PaymentsListPaginated from "../../components/payments-list-paginated/payment-list-paginated.component";
@@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, searchObj } = searchParams;
const { loading, error, data, refetch } = useQuery(

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import { QUERY_PHONEBOOK_PAGINATED } from "../../graphql/phonebook.queries";
@@ -25,7 +25,7 @@ const mapStateToProps = createStructuredSelector({
});
export function PhonebookPageComponent({ bodyshop, authLevel }) {
const searchParams = queryString.parse(useLocation().search);
const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search, phonebookentry } = searchParams;
const history = useNavigate();
@@ -66,7 +66,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
} else {
delete searchParams.statusFilters;
}
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
};
const columns = [
@@ -129,16 +129,16 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
const handleNewPhonebook = () => {
searchParams.phonebookentry = "new";
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
};
const handleOnRowClick = (record) => {
if (record) {
searchParams.phonebookentry = record.id;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
} else {
delete searchParams.phonebookentry;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
}
};
const hasNoAccess = !HasRbacAccess({
@@ -162,7 +162,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
onClick={() => {
delete searchParams.search;
searchParams.page = 1;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
}}
>
{t("general.actions.clear")}
@@ -180,7 +180,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
onSearch={(value) => {
searchParams.search = value;
searchParams.page = 1;
history.push({ search: queryString.stringify(searchParams) });
history({ search: queryString.stringify(searchParams) });
}}
/>
</Space>

View File

@@ -8,9 +8,9 @@ import {
} from "../../redux/application/application.actions";
import PhonebookPage from "./phonebook.page.component";
import { Drawer, Grid } from "antd";
import queryString from "query-string";
import { useNavigate, useLocation } from "react-router-dom";
import { useSearchParams, useNavigate } from "react-router-dom";
import PhonebookFormContainer from "../../components/phonebook-form/phonebook-form.container";
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
@@ -29,13 +29,16 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
},
]);
}, [setBreadcrumbs, t, setSelectedHeader]);
const search = queryString.parse(useLocation().search);
const { phonebookentry } = search;
const history = useNavigate();
const [searchParams] = useSearchParams();
const search = Object.fromEntries(searchParams);
const { phonebookentry } = search;
const navigate = useNavigate();
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
@@ -46,23 +49,23 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
xxl: "45%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
? bpoints[selectedBreakpoint[0]]
: "100%";
return (
<RbacWrapper action="phonebook:view">
<PhonebookPage />
<Drawer
width={drawerPercentage}
onClose={() => {
delete search.phonebookentry;
history.push({ search: queryString.stringify(search) });
}}
visible={phonebookentry}
>
<PhonebookFormContainer />
</Drawer>
</RbacWrapper>
<RbacWrapper action="phonebook:view">
<PhonebookPage />
<Drawer
width={drawerPercentage}
onClose={() => {
searchParams.delete("phonebookentry");
navigate({ search: searchParams.toString() });
}}
visible={phonebookentry}
>
<PhonebookFormContainer />
</Drawer>
</RbacWrapper>
);
}
export default connect(null, mapDispatchToProps)(PhonebookContainer);
export default connect(null, mapDispatchToProps)(PhonebookContainer);

View File

@@ -1,14 +1,13 @@
import queryString from "query-string";
import React from "react";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import UserRequestResetPw from "../../components/user-request-pw-reset/user-request-reset-pw.component";
import UserValidatePwReset from "../../components/user-validate-pw-reset/user-validate-pw-reset.component";
export default function ResetPassword() {
const searchParams = queryString.parse(useLocation().search);
const { mode, oobCode } = searchParams;
const [searchParams] = useSearchParams();
const { mode, oobCode } = Object.fromEntries(searchParams);
if (mode === "resetPassword")
return <UserValidatePwReset oobCode={oobCode} />;
return <UserRequestResetPw />;
}
}

View File

@@ -1,12 +1,9 @@
import Icon, { FieldTimeOutlined } from "@ant-design/icons";
import { Tabs } from "antd";
import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
@@ -17,6 +14,8 @@ import {
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { useNavigate, useSearchParams } from "react-router-dom";
import {createStructuredSelector} from "reselect";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -29,9 +28,9 @@ const mapDispatchToProps = (dispatch) => ({
export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search);
const { tab } = searchParams;
const history = useNavigate();
const [searchParams] = useSearchParams();
const { tab } = Object.fromEntries(searchParams);
const navigate = useNavigate();
useEffect(() => {
document.title = t("titles.scoreboard");
setSelectedHeader("scoreboard");
@@ -44,60 +43,58 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
}, [t, setBreadcrumbs, setSelectedHeader]);
return (
<FeatureWrapper featureName="scoreboard">
<RbacWrapper action="scoreboard:view">
<Tabs
activeKey={tab || "sb"}
destroyInactiveTabPane
onChange={(key) => {
searchParams.tab = key;
history.push({
search: queryString.stringify(searchParams),
});
}}
>
<Tabs.TabPane
tab={
<span>
<FeatureWrapper featureName="scoreboard">
<RbacWrapper action="scoreboard:view">
<Tabs
activeKey={tab || "sb"}
destroyInactiveTabPane
onChange={(key) => {
searchParams.set("tab", key);
navigate({ search: searchParams.toString() });
}}
>
<Tabs.TabPane
tab={
<span>
<Icon component={FaShieldAlt} />
{t("scoreboard.labels.jobs")}
{t("scoreboard.labels.jobs")}
</span>
}
destroyInactiveTabPane
key="sb"
>
<ScoreboardDisplay />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
}
destroyInactiveTabPane
key="sb"
>
<ScoreboardDisplay />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FieldTimeOutlined />
{t("scoreboard.labels.timeticketsemployee")}
{t("scoreboard.labels.timeticketsemployee")}
</span>
}
destroyInactiveTabPane
key="tickets"
>
<ScoreboardTimeTickets />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
}
destroyInactiveTabPane
key="tickets"
>
<ScoreboardTimeTickets />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FieldTimeOutlined />
{t("scoreboard.labels.allemployeetimetickets")}
{t("scoreboard.labels.allemployeetimetickets")}
</span>
}
destroyInactiveTabPane
key="ticketsstats"
>
<ScoreboardTimeTicketsStats />
</Tabs.TabPane>
</Tabs>
</RbacWrapper>
</FeatureWrapper>
}
destroyInactiveTabPane
key="ticketsstats"
>
<ScoreboardTimeTicketsStats />
</Tabs.TabPane>
</Tabs>
</RbacWrapper>
</FeatureWrapper>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ScoreboardContainer);
mapStateToProps,
mapDispatchToProps
)(ScoreboardContainer);

View File

@@ -1,22 +1,19 @@
import { Row, Col } from "antd";
import { useQuery } from "@apollo/client";
import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import CsiResponseFormContainer from "../../components/csi-response-form/csi-response-form.container";
import CsiResponseListPaginated from "../../components/csi-response-list-paginated/csi-response-list-paginated.component";
import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {pageLimit} from "../../utils/config";
import { pageLimit } from "../../utils/config";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
@@ -26,36 +23,30 @@ const mapDispatchToProps = (dispatch) => ({
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
export function ShopCsiContainer({
bodyshop,
setBreadcrumbs,
setSelectedHeader,
}) {
export function ShopCsiContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder } = searchParams;
const [searchParams] = useSearchParams();
const { page, sortcolumn, sortorder } = Object.fromEntries(searchParams);
const { loading, error, data, refetch } = useQuery(
QUERY_CSI_RESPONSE_PAGINATED,
{
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
//search: search || "",
offset: page ? (page - 1) * pageLimit : 0,
limit: pageLimit,
order: [
{
[sortcolumn || "completedon"]: sortorder
? sortorder === "descend"
? "desc_nulls_last"
: "asc"
: "desc_nulls_last",
},
],
},
}
QUERY_CSI_RESPONSE_PAGINATED,
{
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
offset: page ? (page - 1) * pageLimit : 0,
limit: pageLimit,
order: [
{
[sortcolumn || "completedon"]: sortorder
? sortorder === "descend"
? "desc_nulls_last"
: "asc"
: "desc_nulls_last",
},
],
},
}
);
useEffect(() => {
@@ -73,26 +64,21 @@ export function ShopCsiContainer({
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<RbacWrapper
action="csi:page"
// noauth={
// <AlertComponent message="You don't have acess to see this screen." />
// }
>
<Row gutter={16}>
<Col span={10}>
<CsiResponseListPaginated
refetch={refetch}
loading={loading}
responses={data ? data.csi : []}
total={data ? data.csi_aggregate.aggregate.count : 0}
/>
</Col>
<Col span={14}>
<CsiResponseFormContainer />
</Col>
</Row>
</RbacWrapper>
<RbacWrapper action="csi:page">
<Row gutter={16}>
<Col span={10}>
<CsiResponseListPaginated
refetch={refetch}
loading={loading}
responses={data ? data.csi : []}
total={data ? data.csi_aggregate.aggregate.count : 0}
/>
</Col>
<Col span={14}>
<CsiResponseFormContainer />
</Col>
</Row>
</RbacWrapper>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer);
export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer);

View File

@@ -1,45 +1,44 @@
import { Drawer, Grid } from "antd";
import queryString from "query-string";
import React from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { useNavigate, useSearchParams } from "react-router-dom";
import VendorsFormContainer from "../../components/vendors-form/vendors-form.container";
import VendorsListContainer from "../../components/vendors-list/vendors-list.container";
export default function ShopVendorPageComponent() {
const search = queryString.parse(useLocation().search);
const { selectedvendor } = search;
const history = useNavigate();
const [searchParams] = useSearchParams();
const { selectedvendor } = Object.fromEntries(searchParams);
const navigate = useNavigate();
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "50%",
xl: "50%",
xxl: "45%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "50%",
xl: "50%",
xxl: "45%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
return (
<div>
<VendorsListContainer />
return (
<div>
<VendorsListContainer />
<Drawer
width={drawerPercentage}
onClose={() => {
delete search.selectedvendor;
history.push({ search: queryString.stringify(search) });
}}
visible={selectedvendor}
>
<VendorsFormContainer />
</Drawer>
</div>
);
}
<Drawer
width={drawerPercentage}
onClose={() => {
searchParams.delete("selectedvendor");
navigate({ search: searchParams.toString() });
}}
visible={selectedvendor}
>
<VendorsFormContainer />
</Drawer>
</div>
);
}

View File

@@ -1,7 +1,6 @@
import { Tabs } from "antd";
import React, { useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import queryString from "query-string";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container";
import ShopInfoContainer from "../../components/shop-info/shop-info.container";
@@ -26,8 +25,9 @@ const mapDispatchToProps = (dispatch) => ({
export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
const { t } = useTranslation();
const history = useNavigate();
const search = queryString.parse(useLocation().search);
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { tab } = Object.fromEntries(searchParams);
useEffect(() => {
document.title = t("titles.shop");
@@ -41,29 +41,32 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
useEffect(() => {
if (!search.tab) history.push({ search: "?tab=info" });
}, [history, search]);
if (!tab) navigate({ search: "?tab=info" });
}, [navigate, tab]);
return (
<RbacWrapper action="shop:config">
<Tabs
defaultActiveKey={search.tab}
onChange={(key) => history.push({ search: `?tab=${key}` })}
>
<Tabs.TabPane tab={t("bodyshop.labels.shopinfo")} key="info">
<ShopInfoContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees">
<ShopEmployeesContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
<ShopInfoUsersComponent />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq">
<ShopCsiConfig />
</Tabs.TabPane>
</Tabs>
</RbacWrapper>
<RbacWrapper action="shop:config">
<Tabs
defaultActiveKey={tab}
onChange={(key) => {
searchParams.set("tab", key);
navigate({ search: searchParams.toString() });
}}
>
<Tabs.TabPane tab={t("bodyshop.labels.shopinfo")} key="info">
<ShopInfoContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees">
<ShopEmployeesContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
<ShopInfoUsersComponent />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq">
<ShopCsiConfig />
</Tabs.TabPane>
</Tabs>
</RbacWrapper>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(ShopPage);
export default connect(mapStateToProps, mapDispatchToProps)(ShopPage);

View File

@@ -14,29 +14,29 @@ import UpdateAlert from "../../components/update-alert/update-alert.component";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import "./tech.page.styles.scss";
const TimeTicketModalContainer = lazy(() =>
import("../../components/time-ticket-modal/time-ticket-modal.container")
import("../../components/time-ticket-modal/time-ticket-modal.container")
);
const EmailOverlayContainer = lazy(() =>
import("../../components/email-overlay/email-overlay.container.jsx")
import("../../components/email-overlay/email-overlay.container.jsx")
);
const PrintCenterModalContainer = lazy(() =>
import("../../components/print-center-modal/print-center-modal.container")
import("../../components/print-center-modal/print-center-modal.container")
);
const TechLogin = lazy(() =>
import("../../components/tech-login/tech-login.component")
import("../../components/tech-login/tech-login.component")
);
const TechLookup = lazy(() => import("../tech-lookup/tech-lookup.container"));
const ProductionListPage = lazy(() =>
import("../production-list/production-list.container")
import("../production-list/production-list.container")
);
const ProductionBoardPage = lazy(() =>
import("../production-board/production-board.container")
import("../production-board/production-board.container")
);
const TechJobClock = lazy(() =>
import("../tech-job-clock/tech-job-clock.component")
import("../tech-job-clock/tech-job-clock.component")
);
const TechShiftClock = lazy(() =>
import("../tech-shift-clock/tech-shift-clock.component")
import("../tech-shift-clock/tech-shift-clock.component")
);
const { Content } = Layout;
@@ -56,66 +56,41 @@ export function TechPage({ technician, match }) {
document.title = t("titles.app");
}, [t]);
if (!technician) return navigate(`${match.path}/login`
);
return (
<Layout className="tech-layout-container">
<TechSider />
<Layout>
<UpdateAlert />
<TechHeader />
<Layout className="tech-layout-container">
<TechSider />
<Layout>
{technician ? null : navigate(`${match.path}/login`)}
<UpdateAlert />
<TechHeader />
<Content className="tech-content-container">
<ErrorBoundary>
<Suspense
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}
>
<FeatureWrapper featureName="tech-console">
<TimeTicketModalContainer />
<EmailOverlayContainer />
<PrintCenterModalContainer />
<Routes>
<Route
exact
path={`${match.path}/login`}
component={TechLogin}
/>
<Route
exact
path={`${match.path}/joblookup`}
component={TechLookup}
/>
<Route
exact
path={`${match.path}/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/jobclock`}
component={TechJobClock}
/>
<Route
exact
path={`${match.path}/shiftclock`}
component={TechShiftClock}
/>
<Route
exact
path={`${match.path}/board`}
component={ProductionBoardPage}
/>
</Routes>
</FeatureWrapper>
</Suspense>
</ErrorBoundary>
<Content className="tech-content-container">
<ErrorBoundary>
<Suspense
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}
>
<FeatureWrapper featureName="tech-console">
<TimeTicketModalContainer />
<EmailOverlayContainer />
<PrintCenterModalContainer />
<Routes>
<Route path={`${match.path}/login`} element={<TechLogin />} />
<Route path={`${match.path}/joblookup`} element={<TechLookup />} />
<Route path={`${match.path}/list`} element={<ProductionListPage />} />
<Route path={`${match.path}/jobclock`} element={<TechJobClock />} />
<Route path={`${match.path}/shiftclock`} element={<TechShiftClock />} />
<Route path={`${match.path}/board`} element={<ProductionBoardPage />} />
</Routes>
</FeatureWrapper>
</Suspense>
</ErrorBoundary>
<BackTop />
</Content>
<BackTop />
</Content>
</Layout>
</Layout>
</Layout>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(TechPage);
export default connect(mapStateToProps, mapDispatchToProps)(TechPage);

View File

@@ -1,11 +1,10 @@
import { useQuery } from "@apollo/client";
import { Col, Row, Space } from "antd";
import moment from "moment";
import queryString from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
@@ -28,28 +27,17 @@ const mapDispatchToProps = (dispatch) => ({
});
export function TimeTicketsContainer({
bodyshop,
setBreadcrumbs,
setSelectedHeader,
}) {
bodyshop,
setBreadcrumbs,
setSelectedHeader,
}) {
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.timetickets");
setSelectedHeader("timetickets");
setBreadcrumbs([
{
link: "/manage/timetickets",
label: t("titles.bc.timetickets"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
const searchParams = queryString.parse(useLocation().search);
const { start, end } = searchParams;
const [searchParams] = useSearchParams();
const { start, end } = Object.fromEntries(searchParams);
const startDate = start
? moment(start)
: moment().startOf("week").subtract(7, "days");
? moment(start)
: moment().startOf("week").subtract(7, "days");
const endDate = end ? moment(end) : moment().endOf("week");
const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
@@ -61,38 +49,49 @@ export function TimeTicketsContainer({
nextFetchPolicy: "network-only",
});
useEffect(() => {
document.title = t("titles.timetickets");
setSelectedHeader("timetickets");
setBreadcrumbs([
{
link: "/manage/timetickets",
label: t("titles.bc.timetickets"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<RbacWrapper action="timetickets:list">
<Row gutter={[16, 16]}>
<Col span={24}>
<TimeTicketList
loading={loading}
timetickets={data ? data.timetickets : []}
extra={
<Space wrap>
<TimeTicketsAttendanceTable />
<TimeTicketsPayrollTable />
<TimeTicketsDatesSelector />
</Space>
}
/>
</Col>
<Col span={24}>
<TimeTicketsSummaryEmployees
loading={loading}
timetickets={data ? data.timetickets : []}
startDate={startDate}
endDate={endDate}
/>
</Col>
</Row>
</RbacWrapper>
<RbacWrapper action="timetickets:list">
<Row gutter={[16, 16]}>
<Col span={24}>
<TimeTicketList
loading={loading}
timetickets={data ? data.timetickets : []}
extra={
<Space wrap>
<TimeTicketsAttendanceTable />
<TimeTicketsPayrollTable />
<TimeTicketsDatesSelector />
</Space>
}
/>
</Col>
<Col span={24}>
<TimeTicketsSummaryEmployees
loading={loading}
timetickets={data ? data.timetickets : []}
startDate={startDate}
endDate={endDate}
/>
</Col>
</Row>
</RbacWrapper>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TimeTicketsContainer);
mapStateToProps,
mapDispatchToProps
)(TimeTicketsContainer);