diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index aa09ca403..f35958d2a 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -34961,6 +34961,27 @@ + + cardsettings + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + detailpriority false diff --git a/client/package.json b/client/package.json index c90512b78..856e5babf 100644 --- a/client/package.json +++ b/client/package.json @@ -5,9 +5,9 @@ "proxy": "http://localhost:4000", "dependencies": { "@apollo/client": "^3.4.17", + "@asseinfo/react-kanban": "^2.2.0", "@craco/craco": "^6.4.0", "@fingerprintjs/fingerprintjs": "^3.3.0", - "@lourenci/react-kanban": "^2.1.0", "@openreplay/tracker": "^3.4.7", "@openreplay/tracker-assist": "^3.4.4", "@openreplay/tracker-graphql": "^3.0.0", diff --git a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx b/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx index be6fb680a..ec803dbe8 100644 --- a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx +++ b/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx @@ -10,7 +10,12 @@ import { useTranslation } from "react-i18next"; import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component"; import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component"; -export default function ProductionBoardCard(technician, card, bodyshop) { +export default function ProductionBoardCard( + technician, + card, + bodyshop, + cardSettings +) { const { t } = useTranslation(); const menu = (
@@ -39,7 +44,6 @@ export default function ProductionBoardCard(technician, card, bodyshop) { { + form.setFieldsValue( + associationSettings && associationSettings.kanban_settings + ); + }, [form, associationSettings]); + + const { t } = useTranslation(); + + const handleFinish = async (values) => { + const result = await updateKbSettings({ + variables: { + id: associationSettings && associationSettings.id, + ks: values, + }, + }); + }; + + const overlay = ( +
+ +
+ + + + + + + + + + + + + + + +
+
+
+ ); + return ( + + + + ); +} diff --git a/client/src/components/production-board-kanban/production-board-kanban.component.jsx b/client/src/components/production-board-kanban/production-board-kanban.component.jsx index 1c35976f3..6ec3e5155 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.component.jsx @@ -1,6 +1,7 @@ import { useApolloClient } from "@apollo/client"; -import Board, { moveCard } from "@lourenci/react-kanban"; -import "@lourenci/react-kanban/dist/styles.css"; +import Board, { moveCard } from "@asseinfo/react-kanban"; +//import "@asseinfo/react-kanban/dist/styles.css"; +import "./production-board-kanban.styles.scss"; import { notification, PageHeader, Space, Statistic } from "antd"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -16,6 +17,7 @@ import ProductionBoardFilters from "../production-board-filters/production-board import { selectTechnician } from "../../redux/tech/tech.selectors"; import { insertAuditTrail } from "../../redux/application/application.actions"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; +import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -32,6 +34,7 @@ export function ProductionBoardKanbanComponent({ bodyshop, technician, insertAuditTrail, + associationSettings, }) { const [boardLanes, setBoardLanes] = useState({ columns: [{ id: "Loading...", title: "Loading...", cards: [] }], @@ -116,6 +119,7 @@ export function ProductionBoardKanbanComponent({ newChildCard ? newChildCard.id : null, newChildCardNewParent ), + // TODO: optimisticResponse }); insertAuditTrail({ jobid: card.id, @@ -130,6 +134,7 @@ export function ProductionBoardKanbanComponent({ }); } }; + const totalHrs = data .reduce( (acc, val) => @@ -139,6 +144,7 @@ export function ProductionBoardKanbanComponent({ 0 ) .toFixed(1); + return (
@@ -156,18 +162,30 @@ export function ProductionBoardKanbanComponent({ } extra={ - + + + + } /> ProductionBoardCard(technician, card, bodyshop)} + renderCard={(card) => + ProductionBoardCard( + technician, + card, + bodyshop, + associationSettings.kanban_settings + ) + } onCardDragEnd={handleDragEnd} />
diff --git a/client/src/components/production-board-kanban/production-board-kanban.container.jsx b/client/src/components/production-board-kanban/production-board-kanban.container.jsx index 574787213..f8bbdb9fa 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.container.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.container.jsx @@ -1,25 +1,41 @@ -import { useSubscription } from "@apollo/client"; +import { useQuery, useSubscription } from "@apollo/client"; import React from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { getCurrentUser } from "../../firebase/firebase.utils"; import { SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; import ProductionBoardKanbanComponent from "./production-board-kanban.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, + currentUser: selectCurrentUser, }); -export function ProductionBoardKanbanContainer({ bodyshop }) { +export function ProductionBoardKanbanContainer({ bodyshop, currentUser }) { const { loading, data } = useSubscription( SUBSCRIPTION_JOBS_IN_PRODUCTION, {} ); + const { loading: associationSettingsLoading, data: associationSettings } = + useQuery(QUERY_KANBAN_SETTINGS, { + variables: { email: currentUser.email }, + }); + return ( ); } diff --git a/client/src/components/production-board-kanban/production-board-kanban.styles.scss b/client/src/components/production-board-kanban/production-board-kanban.styles.scss new file mode 100644 index 000000000..a6e4533dc --- /dev/null +++ b/client/src/components/production-board-kanban/production-board-kanban.styles.scss @@ -0,0 +1,130 @@ +.react-kanban-board { + padding: 5px; +} +.react-kanban-card { + border-radius: 3px; + background-color: #fff; + padding: 10px; + margin-bottom: 7px; +} +.react-kanban-card-skeleton, +.react-kanban-card, +.react-kanban-card-adder-form { + box-sizing: border-box; + max-width: 250px; + min-width: 250px; +} +.react-kanban-card-skeleton-compact, +.react-kanban-card-compact, +.react-kanban-card-adder-form-compact { + box-sizing: border-box; + max-width: 120px; + min-width: 120px; +} + +.react-kanban-card--dragging { + box-shadow: 2px 2px grey; +} +.react-kanban-card__description { + padding-top: 10px; +} +.react-kanban-card__title { + border-bottom: 1px solid #eee; + padding-bottom: 5px; + font-weight: bold; + display: flex; + justify-content: space-between; +} +.react-kanban-column { + padding: 15px; + border-radius: 2px; + background-color: #eee; + margin: 5px; +} +.react-kanban-column input:focus { + outline: none; +} +.react-kanban-card-adder-form { + border-radius: 3px; + background-color: #fff; + padding: 10px; + margin-bottom: 7px; +} +.react-kanban-card-adder-form input { + border: 0px; + font-family: inherit; + font-size: inherit; +} +.react-kanban-card-adder-button { + width: 100%; + margin-top: 5px; + background-color: transparent; + cursor: pointer; + border: 1px solid #ccc; + transition: 0.3s; + border-radius: 3px; + font-size: 20px; + margin-bottom: 10px; + font-weight: bold; +} +.react-kanban-card-adder-button:hover { + background-color: #ccc; +} +.react-kanban-card-adder-form__title { + font-weight: bold; + border-bottom: 1px solid #eee; + padding-bottom: 5px; + font-weight: bold; + display: flex; + justify-content: space-between; + width: 100%; + padding: 0px; +} +.react-kanban-card-adder-form__title:focus { + outline: none; +} +.react-kanban-card-adder-form__description { + width: 100%; + margin-top: 10px; +} +.react-kanban-card-adder-form__description:focus { + outline: none; +} +.react-kanban-card-adder-form__button { + background-color: #eee; + border: none; + padding: 5px; + width: 45%; + margin-top: 5px; + border-radius: 3px; +} +.react-kanban-card-adder-form__button:hover { + transition: 0.3s; + cursor: pointer; + background-color: #ccc; +} +.react-kanban-column-header { + padding-bottom: 10px; + font-weight: bold; +} +.react-kanban-column-header input:focus { + outline: none; +} +.react-kanban-column-header__button { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} +.react-kanban-column-header__button:hover, +.react-kanban-column-header__button:focus, +.react-kanban-column-header__button:active { + background-color: #e6e6e6; +} +.react-kanban-column-adder-button { + border: 2px dashed #eee; + height: 132px; + margin: 5px; +} +.react-kanban-column-adder-button:hover { + cursor: pointer; +} diff --git a/client/src/graphql/user.queries.js b/client/src/graphql/user.queries.js index 797a4da52..09ba53787 100644 --- a/client/src/graphql/user.queries.js +++ b/client/src/graphql/user.queries.js @@ -69,3 +69,25 @@ export const UPDATE_FCM_TOKEN = gql` } } `; + +export const QUERY_KANBAN_SETTINGS = gql` + query QUERY_KANBAN_SETTINGS($email: String!) { + associations( + where: { _and: { useremail: { _eq: $email }, active: { _eq: true } } } + ) { + id + kanban_settings + } + } +`; +export const UPDATE_KANBAN_SETTINGS = gql` + mutation UPDATE_KANBAN_SETTINGS($id: uuid!, $ks: jsonb) { + update_associations_by_pk( + pk_columns: { id: $id } + _set: { kanban_settings: $ks } + ) { + id + kanban_settings + } + } +`; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 082042e69..568497e8f 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2085,6 +2085,7 @@ "alerton": "Add alert to job", "bodyhours": "B", "bodypriority": "B/P", + "cardsettings": "Card Settings", "detailpriority": "D/P", "employeesearch": "Employee Search", "jobdetail": "Job Details", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index acdaf002d..34dfdccca 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2085,6 +2085,7 @@ "alerton": "", "bodyhours": "", "bodypriority": "", + "cardsettings": "", "detailpriority": "", "employeesearch": "", "jobdetail": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index acade954a..fb91b5d1a 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2085,6 +2085,7 @@ "alerton": "", "bodyhours": "", "bodypriority": "", + "cardsettings": "", "detailpriority": "", "employeesearch": "", "jobdetail": "", diff --git a/client/yarn.lock b/client/yarn.lock index 1219aeafc..d0b3e4e5b 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -54,6 +54,13 @@ tslib "^2.3.0" zen-observable-ts "~1.1.0" +"@asseinfo/react-kanban@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@asseinfo/react-kanban/-/react-kanban-2.2.0.tgz#56b703e9e6d1722a4b2edee321c928fd23749a4d" + integrity sha512-/gCigrNXRHeP9VCo8RipTOrA0vAPRIOThJhR4ibVxe6BLkaWFUEuJ1RMT4fODpRRsE3XsdrfVGKkfpRBKgvxXg== + dependencies: + react-beautiful-dnd "^13.0.0" + "@babel/code-frame@7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" @@ -1977,13 +1984,6 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@lourenci/react-kanban@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@lourenci/react-kanban/-/react-kanban-2.1.0.tgz#1e9ffab30d37a19815adcb1a94cb35817ebee8a9" - integrity sha512-VZK+HbH2DtfQA7RhMWIZAtieN78n6XzJ8EDkKdaOxbefg1FYEJeyQ/GCav6CW7UvWEIAJxBjaYwF+csadIMYFA== - dependencies: - react-beautiful-dnd "^13.0.0" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 3ba629fe1..c97cc49f3 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -203,6 +203,7 @@ - authlevel - default_prod_list_view - id + - kanban_settings - qbo_realmId - shopid - useremail @@ -217,6 +218,7 @@ - active - authlevel - default_prod_list_view + - kanban_settings - qbo_realmId filter: bodyshop: diff --git a/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/down.sql b/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/down.sql new file mode 100644 index 000000000..d2ff6e7a2 --- /dev/null +++ b/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."associations" add column "kanban_settings" jsonb +-- null default jsonb_build_object(); diff --git a/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/up.sql b/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/up.sql new file mode 100644 index 000000000..e18671647 --- /dev/null +++ b/hasura/migrations/1637007938469_alter_table_public_associations_add_column_kanban_settings/up.sql @@ -0,0 +1,2 @@ +alter table "public"."associations" add column "kanban_settings" jsonb + null default jsonb_build_object();