IO-1533 Kanban Customization

This commit is contained in:
Patrick Fic
2021-11-15 13:53:54 -08:00
parent efc2844d99
commit c129b5ba8c
15 changed files with 322 additions and 22 deletions

View File

@@ -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 = (
<div>
@@ -39,7 +44,6 @@ export default function ProductionBoardCard(technician, card, bodyshop) {
<Dropdown overlay={menu} trigger={["contextMenu"]}>
<Card
className="react-kanban-card imex-kanban-card tight-antd-rows"
//style={{ margin: ".2rem 0rem" }}
title={`${card.ro_number || t("general.labels.na")} - ${
card.v_model_yr
} ${card.v_make_desc || ""} ${card.v_model_desc || ""}`}

View File

@@ -0,0 +1,78 @@
import React, { useEffect } from "react";
import { Form, Dropdown, Card, Button, Switch } from "antd";
import { useTranslation } from "react-i18next";
import { useMutation } from "@apollo/client";
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
import { update } from "lodash";
export default function ProductionBoardKanbanCardSettings({
associationSettings,
}) {
const [form] = Form.useForm();
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
useEffect(() => {
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 = (
<div>
<Card>
<Form form={form} onFinish={handleFinish}>
<Form.Item
label={t("production.labels.compact")}
name="compact"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.laborhrs")}
name="laborhrs"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.employeeassignments")}
name="employeeassignments"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.alert")}
name="alert"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.sublets")}
name="sublets"
valuePropName="checked"
>
<Switch />
</Form.Item>
</Form>
</Card>
</div>
);
return (
<Dropdown trigger="click" overlay={overlay}>
<Button>{t("production.labels.cardsettings")}</Button>
</Dropdown>
);
}

View File

@@ -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 (
<div>
<IndefiniteLoading loading={isMoving} />
@@ -156,18 +162,30 @@ export function ProductionBoardKanbanComponent({
</Space>
}
extra={
<ProductionBoardFilters
filter={filter}
setFilter={setFilter}
loading={isMoving}
/>
<Space wrap>
<ProductionBoardFilters
filter={filter}
setFilter={setFilter}
loading={isMoving}
/>
<ProductionBoardKanbanCardSettings
associationSettings={associationSettings}
/>
</Space>
}
/>
<Board
children={boardLanes}
disableCardDrag={isMoving}
renderCard={(card) => ProductionBoardCard(technician, card, bodyshop)}
renderCard={(card) =>
ProductionBoardCard(
technician,
card,
bodyshop,
associationSettings.kanban_settings
)
}
onCardDragEnd={handleDragEnd}
/>
</div>

View File

@@ -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 (
<ProductionBoardKanbanComponent
loading={loading}
loading={loading || associationSettingsLoading}
data={data ? data.jobs : []}
associationSettings={
associationSettings && associationSettings.associations[0]
? associationSettings.associations[0]
: null
}
/>
);
}

View File

@@ -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;
}

View File

@@ -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
}
}
`;

View File

@@ -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",

View File

@@ -2085,6 +2085,7 @@
"alerton": "",
"bodyhours": "",
"bodypriority": "",
"cardsettings": "",
"detailpriority": "",
"employeesearch": "",
"jobdetail": "",

View File

@@ -2085,6 +2085,7 @@
"alerton": "",
"bodyhours": "",
"bodypriority": "",
"cardsettings": "",
"detailpriority": "",
"employeesearch": "",
"jobdetail": "",