From 23c0f8e383a588dc153a41994fdefeacafc1fc2f Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 18 Jan 2024 16:07:17 -0500 Subject: [PATCH 1/8] - update handleBeta Signed-off-by: Dave Richer --- client/src/App/App.jsx | 7 +------ client/src/utils/handleBeta.js | 6 ++++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 7d396eef8..7a4f72c41 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -54,17 +54,12 @@ export function App({ }) { const client = useClient(); - // Handle The Beta Switch. - useEffect(() => { - handleBeta(); - }, []) - - useEffect(() => { if (!navigator.onLine) { setOnline(false); } + handleBeta(); checkUserSession(); }, [checkUserSession, setOnline]); diff --git a/client/src/utils/handleBeta.js b/client/src/utils/handleBeta.js index 428d4fb49..8a1fba468 100644 --- a/client/src/utils/handleBeta.js +++ b/client/src/utils/handleBeta.js @@ -24,12 +24,14 @@ export const handleBeta = () => { // Beta is enabled, but the current host name does start with beta. if (isBeta && !currentHostName.startsWith('beta')) { - window.location.href = `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`; + const href= `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`; + window.location.replace(href); } // Beta is not enabled, but the current host name does start with beta. else if (!isBeta && currentHostName.startsWith('beta')) { - window.location.href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`; + const href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`; + window.location.replace(href); } } export default handleBeta; From e0e62a52be9d082eaa34d355818b8dbf57a4286e Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 18 Jan 2024 13:08:39 -0800 Subject: [PATCH 2/8] Cherry pick schema chengs from IO-2477 --- hasura/metadata/tables.yaml | 74 +++++++++++++++++++ .../down.sql | 1 + .../up.sql | 18 +++++ .../down.sql | 1 + .../up.sql | 18 +++++ 5 files changed, 112 insertions(+) create mode 100644 hasura/migrations/1705522419599_create_table_public_eulas/down.sql create mode 100644 hasura/migrations/1705522419599_create_table_public_eulas/up.sql create mode 100644 hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql create mode 100644 hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 9867b3f8e..f4e4d99a7 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -2423,6 +2423,73 @@ _eq: X-Hasura-User-Id - active: _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: name: exportlog schema: public @@ -5888,6 +5955,13 @@ table: name: email_audit_trail schema: public + - name: eula_acceptances + using: + foreign_key_constraint_on: + column: useremail + table: + name: eula_acceptances + schema: public - name: exportlogs using: foreign_key_constraint_on: diff --git a/hasura/migrations/1705522419599_create_table_public_eulas/down.sql b/hasura/migrations/1705522419599_create_table_public_eulas/down.sql new file mode 100644 index 000000000..bea9117e2 --- /dev/null +++ b/hasura/migrations/1705522419599_create_table_public_eulas/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."eulas"; diff --git a/hasura/migrations/1705522419599_create_table_public_eulas/up.sql b/hasura/migrations/1705522419599_create_table_public_eulas/up.sql new file mode 100644 index 000000000..31eaa5f8d --- /dev/null +++ b/hasura/migrations/1705522419599_create_table_public_eulas/up.sql @@ -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; diff --git a/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql new file mode 100644 index 000000000..29d08ee95 --- /dev/null +++ b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."eula_acceptances"; diff --git a/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql new file mode 100644 index 000000000..18dc09e8e --- /dev/null +++ b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql @@ -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; From 829e6116922665c198cf858f99e48f5b3f258012 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 18 Jan 2024 16:16:06 -0500 Subject: [PATCH 3/8] - update handleBeta Signed-off-by: Dave Richer --- client/src/App/App.jsx | 3 +-- client/src/utils/handleBeta.js | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 7a4f72c41..2aae995c8 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -58,9 +58,8 @@ export function App({ if (!navigator.onLine) { setOnline(false); } - - handleBeta(); checkUserSession(); + handleBeta(); }, [checkUserSession, setOnline]); //const b = Grid.useBreakpoint(); diff --git a/client/src/utils/handleBeta.js b/client/src/utils/handleBeta.js index 8a1fba468..e1d8199c4 100644 --- a/client/src/utils/handleBeta.js +++ b/client/src/utils/handleBeta.js @@ -26,12 +26,14 @@ export const handleBeta = () => { if (isBeta && !currentHostName.startsWith('beta')) { const href= `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`; window.location.replace(href); + window.location.reload(true); } // Beta is not enabled, but the current host name does start with beta. else if (!isBeta && currentHostName.startsWith('beta')) { const href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`; window.location.replace(href); + window.location.reload(true) } } export default handleBeta; From 0cab47f9849be095c82be5cd14eb12a4e89e836e Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 18 Jan 2024 16:22:58 -0500 Subject: [PATCH 4/8] - update handleBeta Signed-off-by: Dave Richer --- client/src/App/App.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 2aae995c8..2def5eaf2 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -59,7 +59,6 @@ export function App({ setOnline(false); } checkUserSession(); - handleBeta(); }, [checkUserSession, setOnline]); //const b = Grid.useBreakpoint(); @@ -108,6 +107,8 @@ export function App({ /> ); + handleBeta(); + return ( }> From bf6b1c202fa4292333302fcaae28da97b1ee5554 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 18 Jan 2024 16:35:30 -0500 Subject: [PATCH 5/8] - update handleBeta Signed-off-by: Dave Richer --- client/src/App/App.jsx | 1 + client/src/utils/handleBeta.js | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 2def5eaf2..4f074e5e9 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -73,6 +73,7 @@ export function App({ window.addEventListener("online", function (e) { setOnline(true); }); + useEffect(() => { if (currentUser.authorized && bodyshop) { client.setAttribute("imexshopid", bodyshop.imexshopid); diff --git a/client/src/utils/handleBeta.js b/client/src/utils/handleBeta.js index e1d8199c4..8a1fba468 100644 --- a/client/src/utils/handleBeta.js +++ b/client/src/utils/handleBeta.js @@ -26,14 +26,12 @@ export const handleBeta = () => { if (isBeta && !currentHostName.startsWith('beta')) { const href= `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`; window.location.replace(href); - window.location.reload(true); } // Beta is not enabled, but the current host name does start with beta. else if (!isBeta && currentHostName.startsWith('beta')) { const href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`; window.location.replace(href); - window.location.reload(true) } } export default handleBeta; From cb8632641e0894fa1e7973e6bc13067297209bea Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 18 Jan 2024 17:28:46 -0800 Subject: [PATCH 6/8] IO-2608 Filter and Sort columns in Employee table --- .../shop-employees-list.component.jsx | 77 ++++++++++++++++--- client/src/graphql/employees.queries.js | 7 +- client/src/translations/en_us/common.json | 3 + client/src/translations/es/common.json | 3 + client/src/translations/fr/common.json | 3 + 5 files changed, 80 insertions(+), 13 deletions(-) diff --git a/client/src/components/shop-employees/shop-employees-list.component.jsx b/client/src/components/shop-employees/shop-employees-list.component.jsx index 416e875f9..dd540745f 100644 --- a/client/src/components/shop-employees/shop-employees-list.component.jsx +++ b/client/src/components/shop-employees/shop-employees-list.component.jsx @@ -1,14 +1,20 @@ import { Button, Table } from "antd"; import queryString from "query-string"; -import React from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { useHistory, useLocation } from "react-router-dom"; +import { alphaSort } from "../../utils/sorters"; export default function ShopEmployeesListComponent({ loading, employees }) { const { t } = useTranslation(); const history = useHistory(); const search = queryString.parse(useLocation().search); + const [state, setState] = useState({ + sortedInfo: {}, + filteredInfo: { text: "" }, + }); + const handleOnRowClick = (record) => { if (record) { search.employeeId = record.id; @@ -18,32 +24,82 @@ export default function ShopEmployeesListComponent({ loading, employees }) { history.push({ search: queryString.stringify(search) }); } }; + + const handleTableChange = (pagination, filters, sorter) => { + setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); + }; + const columns = [ { title: t("employees.fields.employee_number"), dataIndex: "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"), - dataIndex: "first_name", - key: "first_name", + title: t("employees.labels.name"), + dataIndex: "employee_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"), dataIndex: "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) => record.flat_rate ? t("employees.labels.flat_rate") : 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 (
@@ -74,6 +130,7 @@ export default function ShopEmployeesListComponent({ loading, employees }) { type: "radio", selectedRowKeys: [search.employeeId], }} + onChange={handleTableChange} onRow={(record, rowIndex) => { return { onClick: (event) => { diff --git a/client/src/graphql/employees.queries.js b/client/src/graphql/employees.queries.js index 207c10bab..e34d2be3b 100644 --- a/client/src/graphql/employees.queries.js +++ b/client/src/graphql/employees.queries.js @@ -3,11 +3,12 @@ import { gql } from "@apollo/client"; export const QUERY_EMPLOYEES = gql` query QUERY_EMPLOYEES { employees(order_by: { employee_number: asc }) { - last_name - id + active + employee_number first_name flat_rate - employee_number + id + last_name } } `; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 09798f0a5..4842927d6 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1001,10 +1001,13 @@ }, "labels": { "actions": "Actions", + "active": "Active", "endmustbeafterstart": "End date must be after start date.", "flat_rate": "Flat Rate", + "inactive": "Inactive", "name": "Name", "rate_type": "Rate Type", + "status": "Status", "straight_time": "Straight Time" }, "successes": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index da9f6b4e0..4e96502e2 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1001,10 +1001,13 @@ }, "labels": { "actions": "", + "active": "", "endmustbeafterstart": "", "flat_rate": "", + "inactive": "", "name": "", "rate_type": "", + "status": "", "straight_time": "" }, "successes": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index a4c1dc686..707f2f16a 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1001,10 +1001,13 @@ }, "labels": { "actions": "", + "active": "", "endmustbeafterstart": "", "flat_rate": "", + "inactive": "", "name": "", "rate_type": "", + "status": "", "straight_time": "" }, "successes": { From 51483f62e1d8bc1145f20b932d916ffd97119b7d Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 18 Jan 2024 20:49:50 -0500 Subject: [PATCH 7/8] - optimize schedule out today in dashboard Signed-off-by: Dave Richer --- .../scheduled-out-today.component.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/components/dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx b/client/src/components/dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx index 0c794f1db..2d167c330 100644 --- a/client/src/components/dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx +++ b/client/src/components/dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx @@ -22,12 +22,13 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) { if (!data.scheduled_out_today) return ; - data.scheduled_out_today.forEach((item) => { - item.scheduled_completion= dayjs(item.scheduled_completion).format("hh:mm a") - }); - data.scheduled_out_today.sort(function (a, b) { - return new Date(a.scheduled_completion) - new Date(b.scheduled_completion); - }); + const filteredScheduledOutToday = data.scheduled_out_today.map((item) => { + return { + ...item, + scheduled_completion: dayjs(item.scheduled_completion).format("hh:mm a"), + timestamp: dayjs(item.scheduled_completion).valueOf(), + } + }).sort((a, b) => a.timestamp - b.timestamp); const columns = [ { @@ -171,7 +172,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) { scroll={{ x: true, y: "calc(100% - 2em)" }} rowKey="id" style={{ height: "85%" }} - dataSource={data.scheduled_out_today} + dataSource={filteredScheduledOutToday} />
From d06037df1fea4e825e808173570bd2717c88ff7c Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 19 Jan 2024 08:47:17 -0800 Subject: [PATCH 8/8] IO-2598 Restrict IOU from Tech Console --- .../job-create-iou.component.jsx | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/client/src/components/job-create-iou/job-create-iou.component.jsx b/client/src/components/job-create-iou/job-create-iou.component.jsx index 8ebc8fb75..930f27e25 100644 --- a/client/src/components/job-create-iou/job-create-iou.component.jsx +++ b/client/src/components/job-create-iou/job-create-iou.component.jsx @@ -7,21 +7,31 @@ import { connect } from "react-redux"; import { useHistory } from "react-router"; import { createStructuredSelector } from "reselect"; import { UPDATE_JOB_LINES_IOU } from "../../graphql/jobs-lines.queries"; +import { selectTechnician } from "../../redux/tech/tech.selectors"; import { selectBodyshop, selectCurrentUser, } from "../../redux/user/user.selectors"; import { CreateIouForJob } from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util"; + const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, currentUser: selectCurrentUser, + technician: selectTechnician, }); + const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); 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 [loading, setLoading] = useState(false); const client = useApolloClient(); @@ -79,13 +89,19 @@ export function JobCreateIOU({ bodyshop, currentUser, job, selectedJobLines }) { title={t("jobs.labels.createiouwarning")} onConfirm={handleCreateIou} disabled={ - !selectedJobLines || selectedJobLines.length === 0 || !job.converted + !selectedJobLines || + selectedJobLines.length === 0 || + !job.converted || + technician } >