Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-19 12:29:04 -05:00
11 changed files with 300 additions and 119 deletions

View File

@@ -9,17 +9,20 @@ import {createStructuredSelector} from "reselect";
import {UPDATE_JOB_LINES_IOU} from "../../graphql/jobs-lines.queries"; import {UPDATE_JOB_LINES_IOU} from "../../graphql/jobs-lines.queries";
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors"; import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import {CreateIouForJob} from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util"; import {CreateIouForJob} from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util";
import {selectTechnician} from "../../redux/tech/tech.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
technician: selectTechnician,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobCreateIOU); export default connect(mapStateToProps, mapDispatchToProps)(JobCreateIOU);
export function JobCreateIOU({bodyshop, currentUser, job, selectedJobLines}) { export function JobCreateIOU({bodyshop, currentUser, job, selectedJobLines, technician}) {
const {t} = useTranslation(); const {t} = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const client = useApolloClient(); const client = useApolloClient();
@@ -79,13 +82,13 @@ export function JobCreateIOU({bodyshop, currentUser, job, selectedJobLines}) {
title={t("jobs.labels.createiouwarning")} title={t("jobs.labels.createiouwarning")}
onConfirm={handleCreateIou} onConfirm={handleCreateIou}
disabled={ disabled={
!selectedJobLines || selectedJobLines.length === 0 || !job.converted !selectedJobLines || selectedJobLines.length === 0 || !job.converted || technician
} }
> >
<Button <Button
loading={loading} loading={loading}
disabled={ disabled={
!selectedJobLines || selectedJobLines.length === 0 || !job.converted !selectedJobLines || selectedJobLines.length === 0 || !job.converted || technician
} }
> >
{t("jobs.actions.createiou")} {t("jobs.actions.createiou")}

View File

@@ -1,13 +1,20 @@
import {Button, Table} from "antd"; import {Button, Table} from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React, {useState} from "react";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
import {useLocation, useNavigate} from "react-router-dom"; import {useLocation, useNavigate} from "react-router-dom";
import {alphaSort} from "../../utils/sorters";
export default function ShopEmployeesListComponent({loading, employees}) { export default function ShopEmployeesListComponent({loading, employees}) {
const {t} = useTranslation(); const {t} = useTranslation();
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {text: ""},
});
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
search.employeeId = record.id; search.employeeId = record.id;
@@ -17,32 +24,80 @@ export default function ShopEmployeesListComponent({loading, employees}) {
history({search: queryString.stringify(search)}); history({search: queryString.stringify(search)});
} }
}; };
const handleTableChange = (pagination, filters, sorter) => {
setState({...state, filteredInfo: filters, sortedInfo: sorter});
};
const columns = [ const columns = [
{ {
title: t("employees.fields.employee_number"), title: t("employees.fields.employee_number"),
dataIndex: "employee_number", dataIndex: "employee_number",
key: "employee_number", key: "employee_number",
sorter: (a, b) => alphaSort(a.employee_number, b.employee_number),
sortOrder:
state.sortedInfo.columnKey === "employee_number" &&
state.sortedInfo.order,
}, },
{ {
title: t("employees.fields.first_name"), title: t("employees.labels.name"),
dataIndex: "first_name", dataIndex: "employee_name",
key: "first_name", key: "employee_name",
sorter: (a, b) =>
alphaSort(
`${a.first_name || ""} ${a.last_name || ""}`.trim(),
`${b.first_name || ""} ${b.last_name || ""}`.trim()
),
sortOrder:
state.sortedInfo.columnKey === "employee_name" &&
state.sortedInfo.order,
render: (text, record) =>
`${record.first_name || ""} ${record.last_name || ""}`.trim(),
}, },
{
title: t("employees.fields.last_name"),
dataIndex: "last_name",
key: "last_name",
},
{ {
title: t("employees.labels.rate_type"), title: t("employees.labels.rate_type"),
dataIndex: "rate_type", dataIndex: "rate_type",
key: "rate_type", key: "rate_type",
sorter: (a, b) => Number(a.flat_rate) - Number(b.flat_rate),
sortOrder:
state.sortedInfo.columnKey === "rate_type" && state.sortedInfo.order,
filters: [
{
text: t("employees.labels.flat_rate"),
value: true,
},
{
text: t("employees.labels.straight_time"),
value: false,
},
],
onFilter: (value, record) => value === record.flate_rate,
render: (text, record) => render: (text, record) =>
record.flat_rate record.flat_rate
? t("employees.labels.flat_rate") ? t("employees.labels.flat_rate")
: t("employees.labels.straight_time"), : t("employees.labels.straight_time"),
}, },
{
title: t("employees.labels.status"),
dataIndex: "active",
key: "active",
sorter: (a, b) => Number(a.active) - Number(b.active),
sortOrder:
state.sortedInfo.columnKey === "active" && state.sortedInfo.order,
filters: [
{
text: t("employees.labels.active"),
value: true,
},
{
text: t("employees.labels.inactive"),
value: false,
},
],
onFilter: (value, record) => value === record.active,
render: (text, record) =>
record.active
? t("employees.labels.active")
: t("employees.labels.inactive"),
},
]; ];
return ( return (
<div> <div>
@@ -73,6 +128,7 @@ export default function ShopEmployeesListComponent({loading, employees}) {
type: "radio", type: "radio",
selectedRowKeys: [search.employeeId], selectedRowKeys: [search.employeeId],
}} }}
onChange={handleTableChange}
onRow={(record, rowIndex) => { onRow={(record, rowIndex) => {
return { return {
onClick: (event) => { onClick: (event) => {

View File

@@ -1,145 +1,146 @@
import { gql } from "@apollo/client"; import {gql} from "@apollo/client";
export const QUERY_EMPLOYEES = gql` export const QUERY_EMPLOYEES = gql`
query QUERY_EMPLOYEES { query QUERY_EMPLOYEES {
employees(order_by: { employee_number: asc }) { employees(order_by: { employee_number: asc }) {
last_name active
id employee_number
first_name first_name
flat_rate flat_rate
employee_number id
last_name
}
} }
}
`; `;
export const QUERY_EMPLOYEE_BY_ID = gql` export const QUERY_EMPLOYEE_BY_ID = gql`
query QUERY_EMPLOYEE_BY_ID($id: uuid!) { query QUERY_EMPLOYEE_BY_ID($id: uuid!) {
employees_by_pk(id: $id) { employees_by_pk(id: $id) {
last_name last_name
id id
first_name first_name
employee_number employee_number
active active
termination_date termination_date
hire_date hire_date
flat_rate flat_rate
rates rates
pin pin
user_email user_email
external_id external_id
employee_vacations(order_by: { start: desc }) { employee_vacations(order_by: { start: desc }) {
id id
start start
end end
} }
}
} }
}
`; `;
export const CHECK_EMPLOYEE_NUMBER = gql` export const CHECK_EMPLOYEE_NUMBER = gql`
query CHECK_EMPLOYEE_NUMBER($employeenumber: String!) { query CHECK_EMPLOYEE_NUMBER($employeenumber: String!) {
employees_aggregate( employees_aggregate(
where: { employee_number: { _ilike: $employeenumber } } where: { employee_number: { _ilike: $employeenumber } }
) { ) {
aggregate { aggregate {
count count
} }
nodes { nodes {
id id
} }
}
} }
}
`; `;
export const QUERY_ACTIVE_EMPLOYEES = gql` export const QUERY_ACTIVE_EMPLOYEES = gql`
query QUERY_ACTIVE_EMPLOYEES { query QUERY_ACTIVE_EMPLOYEES {
employees(where: { active: { _eq: true } }) { employees(where: { active: { _eq: true } }) {
last_name last_name
id id
first_name first_name
employee_number employee_number
active active
termination_date termination_date
hire_date hire_date
flat_rate flat_rate
rates rates
pin pin
user_email user_email
}
} }
}
`; `;
export const INSERT_EMPLOYEES = gql` export const INSERT_EMPLOYEES = gql`
mutation INSERT_EMPLOYEES($employees: [employees_insert_input!]!) { mutation INSERT_EMPLOYEES($employees: [employees_insert_input!]!) {
insert_employees(objects: $employees) { insert_employees(objects: $employees) {
returning { returning {
last_name last_name
id id
first_name first_name
employee_number employee_number
active active
termination_date termination_date
hire_date hire_date
flat_rate flat_rate
rates rates
pin pin
user_email user_email
} }
}
} }
}
`; `;
export const UPDATE_EMPLOYEE = gql` export const UPDATE_EMPLOYEE = gql`
mutation UPDATE_EMPLOYEE($id: uuid!, $employee: employees_set_input) { mutation UPDATE_EMPLOYEE($id: uuid!, $employee: employees_set_input) {
update_employees(where: { id: { _eq: $id } }, _set: $employee) { update_employees(where: { id: { _eq: $id } }, _set: $employee) {
returning { returning {
last_name last_name
id id
first_name first_name
employee_number employee_number
active active
termination_date termination_date
hire_date hire_date
flat_rate flat_rate
rates rates
pin pin
user_email user_email
} }
}
} }
}
`; `;
export const DELETE_EMPLOYEE = gql` export const DELETE_EMPLOYEE = gql`
mutation DELETE_EMPLOYEE($id: uuid!) { mutation DELETE_EMPLOYEE($id: uuid!) {
delete_employees(where: { id: { _eq: $id } }) { delete_employees(where: { id: { _eq: $id } }) {
returning { returning {
id id
} }
}
} }
}
`; `;
export const QUERY_USERS_BY_EMAIL = gql` export const QUERY_USERS_BY_EMAIL = gql`
query QUERY_USERS_BY_EMAIL($email: String!) { query QUERY_USERS_BY_EMAIL($email: String!) {
users(where: { email: { _ilike: $email } }) { users(where: { email: { _ilike: $email } }) {
email email
}
} }
}
`; `;
export const INSERT_VACATION = gql` export const INSERT_VACATION = gql`
mutation INSERT_VACATION($vacation: employee_vacation_insert_input!) { mutation INSERT_VACATION($vacation: employee_vacation_insert_input!) {
insert_employee_vacation_one(object: $vacation) { insert_employee_vacation_one(object: $vacation) {
id id
start start
end end
}
} }
}
`; `;
export const DELETE_VACATION = gql` export const DELETE_VACATION = gql`
mutation DELETE_VACATION($id: uuid!) { mutation DELETE_VACATION($id: uuid!) {
delete_employee_vacation_by_pk(id: $id) { delete_employee_vacation_by_pk(id: $id) {
id id
}
} }
}
`; `;

View File

@@ -1015,10 +1015,13 @@
}, },
"labels": { "labels": {
"actions": "Actions", "actions": "Actions",
"active": "Active",
"endmustbeafterstart": "End date must be after start date.", "endmustbeafterstart": "End date must be after start date.",
"flat_rate": "Flat Rate", "flat_rate": "Flat Rate",
"inactive": "Inactive",
"name": "Name", "name": "Name",
"rate_type": "Rate Type", "rate_type": "Rate Type",
"status": "Status",
"straight_time": "Straight Time" "straight_time": "Straight Time"
}, },
"successes": { "successes": {

View File

@@ -1015,10 +1015,13 @@
}, },
"labels": { "labels": {
"actions": "", "actions": "",
"active": "",
"endmustbeafterstart": "", "endmustbeafterstart": "",
"flat_rate": "", "flat_rate": "",
"inactive": "",
"name": "", "name": "",
"rate_type": "", "rate_type": "",
"status": "",
"straight_time": "" "straight_time": ""
}, },
"successes": { "successes": {

View File

@@ -1015,10 +1015,13 @@
}, },
"labels": { "labels": {
"actions": "", "actions": "",
"active": "",
"endmustbeafterstart": "", "endmustbeafterstart": "",
"flat_rate": "", "flat_rate": "",
"inactive": "",
"name": "", "name": "",
"rate_type": "", "rate_type": "",
"status": "",
"straight_time": "" "straight_time": ""
}, },
"successes": { "successes": {

View File

@@ -2423,6 +2423,73 @@
_eq: X-Hasura-User-Id _eq: X-Hasura-User-Id
- active: - active:
_eq: true _eq: true
- table:
name: eula_acceptances
schema: public
object_relationships:
- name: eula
using:
foreign_key_constraint_on: eulaid
- name: user
using:
foreign_key_constraint_on: useremail
insert_permissions:
- role: user
permission:
check:
user:
authid:
_eq: X-Hasura-User-Id
columns:
- address
- buisness_name
- date_accepted
- eulaid
- first_name
- last_name
- phone_number
- useremail
select_permissions:
- role: user
permission:
columns:
- address
- buisness_name
- first_name
- last_name
- phone_number
- useremail
- created_at
- date_accepted
- updated_at
- eulaid
- id
filter:
user:
authid:
_eq: X-Hasura-User-Id
- table:
name: eulas
schema: public
array_relationships:
- name: eula_acceptances
using:
foreign_key_constraint_on:
column: eulaid
table:
name: eula_acceptances
schema: public
select_permissions:
- role: user
permission:
columns:
- id
- created_at
- updated_at
- effective_date
- end_date
- content
filter: {}
- table: - table:
name: exportlog name: exportlog
schema: public schema: public
@@ -5888,6 +5955,13 @@
table: table:
name: email_audit_trail name: email_audit_trail
schema: public schema: public
- name: eula_acceptances
using:
foreign_key_constraint_on:
column: useremail
table:
name: eula_acceptances
schema: public
- name: exportlogs - name: exportlogs
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:

View File

@@ -0,0 +1 @@
DROP TABLE "public"."eulas";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."eulas" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "effective_date" timestamptz NOT NULL, "end_date" timestamptz, "content" text NOT NULL, PRIMARY KEY ("id") );
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_eulas_updated_at"
BEFORE UPDATE ON "public"."eulas"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_eulas_updated_at" ON "public"."eulas"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -0,0 +1 @@
DROP TABLE "public"."eula_acceptances";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."eula_acceptances" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "eulaid" uuid NOT NULL, "date_accepted" timestamptz NOT NULL, "first_name" text NOT NULL, "last_name" text NOT NULL, "address" text NOT NULL, "phone_number" Text NOT NULL, "buisness_name" Text NOT NULL, "useremail" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("eulaid") REFERENCES "public"."eulas"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("useremail") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_eula_acceptances_updated_at"
BEFORE UPDATE ON "public"."eula_acceptances"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_eula_acceptances_updated_at" ON "public"."eula_acceptances"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;