Added status changing information

This commit is contained in:
Patrick Fic
2020-02-06 16:33:23 -08:00
parent f00ae5335f
commit d422edcb0e
15 changed files with 176 additions and 18 deletions

View File

@@ -420,6 +420,37 @@
</folder_node> </folder_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>bodyshop</name>
<children>
<folder_node>
<name>errors</name>
<children>
<concept_node>
<name>loading</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
<folder_node> <folder_node>
<name>documents</name> <name>documents</name>
<children> <children>
@@ -1069,6 +1100,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>changestatus</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>convert</name> <name>convert</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -28,14 +28,15 @@ const mapDispatchToProps = dispatch => ({
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(({ checkUserSession, currentUser }) => { )(({ checkUserSession, currentUser, setBodyshop }) => {
useEffect(() => { useEffect(() => {
checkUserSession(); checkUserSession();
return () => {}; return () => {};
}, [checkUserSession]); }, [checkUserSession]);
if (false) if (currentUser && currentUser.language)
i18next.changeLanguage("en_US", (err, t) => { i18next.changeLanguage(currentUser.language, (err, t) => {
if (err) if (err)
return console.log("Error encountered when changing languages.", err); return console.log("Error encountered when changing languages.", err);
}); });

View File

@@ -1,26 +1,41 @@
import { import {
Avatar, Avatar,
Badge,
Button, Button,
Checkbox, Checkbox,
Descriptions, Descriptions,
Dropdown,
Icon,
Menu,
notification, notification,
PageHeader, PageHeader,
Tag, Tag
Badge
} from "antd"; } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Moment from "react-moment"; import Moment from "react-moment";
import { connect } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import CarImage from "../../assets/car.svg"; import CarImage from "../../assets/car.svg";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
export default function JobsDetailHeader({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
export default connect(
mapStateToProps,
null
)(function JobsDetailHeader({
job, job,
mutationConvertJob, mutationConvertJob,
refetch, refetch,
handleSubmit, handleSubmit,
scheduleModalState scheduleModalState,
bodyshop,
updateJobStatus
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const setscheduleModalVisible = scheduleModalState[1]; const setscheduleModalVisible = scheduleModalState[1];
@@ -60,7 +75,26 @@ export default function JobsDetailHeader({
</div> </div>
); );
const statusmenu = (
<Menu
onClick={e => {
updateJobStatus({
variables: { jobId: job.id, status: e.key }
}).then(r => refetch());
}}
>
{bodyshop.md_ro_statuses.statuses.map(item => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
</Menu>
);
const menuExtra = [ const menuExtra = [
<Dropdown overlay={statusmenu} key="changestatus">
<Button>
{t("jobs.actions.changestatus")} <Icon type="down" />
</Button>
</Dropdown>,
<Badge key="schedule" count={job.appointments_aggregate.aggregate.count}> <Badge key="schedule" count={job.appointments_aggregate.aggregate.count}>
<Button <Button
//TODO: Enabled logic based on status. //TODO: Enabled logic based on status.
@@ -138,4 +172,4 @@ export default function JobsDetailHeader({
</Descriptions> </Descriptions>
</PageHeader> </PageHeader>
); );
} });

View File

@@ -19,6 +19,7 @@ export const QUERY_BODYSHOP = gql`
state_tax_id state_tax_id
updated_at updated_at
zip_post zip_post
region_config
} }
} }
`; `;

View File

@@ -321,3 +321,13 @@ export const INSERT_NEW_JOB = gql`
} }
} }
`; `;
export const UPDATE_JOB_STATUS = gql`
mutation UPDATE_JOB_STATUS($jobId: uuid!, $status: String!) {
update_jobs(where: { id: { _eq: $jobId } }, _set: { status: $status }) {
returning {
id
}
}
}
`;

View File

@@ -24,7 +24,8 @@ export default function JobsDetailPage({
mutationConvertJob, mutationConvertJob,
handleSubmit, handleSubmit,
refetch, refetch,
scheduleModalState scheduleModalState,
updateJobStatus
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -55,6 +56,7 @@ export default function JobsDetailPage({
refetch={refetch} refetch={refetch}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
scheduleModalState={scheduleModalState} scheduleModalState={scheduleModalState}
updateJobStatus={updateJobStatus}
/> />
{isFieldsTouched() ? ( {isFieldsTouched() ? (

View File

@@ -7,7 +7,8 @@ import SpinComponent from "../../components/loading-spinner/loading-spinner.comp
import { import {
CONVERT_JOB_TO_RO, CONVERT_JOB_TO_RO,
GET_JOB_BY_PK, GET_JOB_BY_PK,
UPDATE_JOB UPDATE_JOB,
UPDATE_JOB_STATUS
} from "../../graphql/jobs.queries"; } from "../../graphql/jobs.queries";
import JobsDetailPage from "./jobs-detail.page.component"; import JobsDetailPage from "./jobs-detail.page.component";
import JobDetailFormContext from "./jobs-detail.page.context"; import JobDetailFormContext from "./jobs-detail.page.context";
@@ -24,7 +25,7 @@ function JobsDetailPageContainer({ match, form }) {
}); });
const [mutationUpdateJob] = useMutation(UPDATE_JOB); const [mutationUpdateJob] = useMutation(UPDATE_JOB);
const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO); const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO);
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
useEffect(() => { useEffect(() => {
document.title = loading document.title = loading
? t("titles.app") ? t("titles.app")
@@ -74,6 +75,7 @@ function JobsDetailPageContainer({ match, form }) {
getFieldDecorator={form.getFieldDecorator} getFieldDecorator={form.getFieldDecorator}
refetch={refetch} refetch={refetch}
scheduleModalState={scheduleModalState} scheduleModalState={scheduleModalState}
updateJobStatus={updateJobStatus}
/> />
</JobDetailFormContext.Provider> </JobDetailFormContext.Provider>
) : ( ) : (

View File

@@ -1,15 +1,21 @@
import { BackTop, Layout } from "antd"; import { BackTop, Layout, notification } from "antd";
import React, { lazy, Suspense, useEffect } from "react"; import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
//This page will handle all routing for the entire application.
import { connect } from "react-redux";
import { Route } from "react-router"; import { Route } from "react-router";
import { createStructuredSelector } from "reselect";
import { useQuery } from "react-apollo";
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import ErrorBoundary from "../../components/error-boundary/error-boundary.component"; import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
import FooterComponent from "../../components/footer/footer.component"; import FooterComponent from "../../components/footer/footer.component";
//Component Imports //Component Imports
import HeaderContainer from "../../components/header/header.container"; import HeaderContainer from "../../components/header/header.container";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
//const WhiteBoardPage = lazy(() => import("../white-board/white-board.page"));
import { setBodyshop } from "../../redux/user/user.actions";
import "./manage.page.styles.scss"; import "./manage.page.styles.scss";
//const WhiteBoardPage = lazy(() => import("../white-board/white-board.page"));
const ManageRootPage = lazy(() => const ManageRootPage = lazy(() =>
import("../manage-root/manage-root.page.container") import("../manage-root/manage-root.page.container")
); );
@@ -32,10 +38,27 @@ const ScheduleContainer = lazy(() =>
); );
const { Header, Content, Footer } = Layout; const { Header, Content, Footer } = Layout;
//This page will handle all routing for the entire application.
export default function Manage({ match }) { const mapDispatchToProps = dispatch => ({
setBodyshop: bs => dispatch(setBodyshop(bs))
});
export default connect(
null,
mapDispatchToProps
)(function Manage({ match, setBodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { error, data } = useQuery(QUERY_BODYSHOP, {
fetchPolicy: "network-only"
});
if (error) {
notification["error"]({ message: t("bodyshop.errors.loading") });
}
if (data) {
setBodyshop(data.bodyshops[0]);
}
useEffect(() => { useEffect(() => {
document.title = t("titles.app"); document.title = t("titles.app");
}, [t]); }, [t]);
@@ -96,4 +119,4 @@ export default function Manage({ match }) {
<BackTop /> <BackTop />
</Layout> </Layout>
); );
} });

View File

@@ -48,3 +48,8 @@ export const updateUserDetailsSuccess = userDetails => ({
type: UserActionTypes.UPDATE_USER_DETAILS_SUCCESS, type: UserActionTypes.UPDATE_USER_DETAILS_SUCCESS,
payload: userDetails payload: userDetails
}); });
export const setBodyshop = bodyshop => ({
type: UserActionTypes.SET_SHOP_DETAILS,
payload: bodyshop
});

View File

@@ -3,8 +3,9 @@ import UserActionTypes from "./user.types";
const INITIAL_STATE = { const INITIAL_STATE = {
currentUser: { currentUser: {
authorized: null, authorized: null,
language: "en_US" language: "en_us"
}, },
bodyshop: null,
error: null error: null
}; };
@@ -41,6 +42,9 @@ const userReducer = (state = INITIAL_STATE, action) => {
...action.payload //Spread current user details in. ...action.payload //Spread current user details in.
} }
}; };
case UserActionTypes.SET_SHOP_DETAILS:
return { ...state, bodyshop: action.payload };
case UserActionTypes.SIGN_IN_FAILURE: case UserActionTypes.SIGN_IN_FAILURE:
case UserActionTypes.SIGN_OUT_FAILURE: case UserActionTypes.SIGN_OUT_FAILURE:
case UserActionTypes.EMAIL_SIGN_UP_FAILURE: case UserActionTypes.EMAIL_SIGN_UP_FAILURE:

View File

@@ -11,3 +11,8 @@ export const selectSignInError = createSelector(
[selectUser], [selectUser],
user => user.error user => user.error
); );
export const selectBodyshop = createSelector(
[selectUser],
user => user.bodyshop
);

View File

@@ -14,6 +14,7 @@ const UserActionTypes = {
UNAUTHORIZED_USER: "UNAUTHORIZED_USER", UNAUTHORIZED_USER: "UNAUTHORIZED_USER",
SET_USER_LANGUAGE: "SET_USER_LANGUAGE", SET_USER_LANGUAGE: "SET_USER_LANGUAGE",
UPDATE_USER_DETAILS: "UPDATE_USER_DETAILS", UPDATE_USER_DETAILS: "UPDATE_USER_DETAILS",
UPDATE_USER_DETAILS_SUCCESS: "UPDATE_USER_DETAILS_SUCCESS" UPDATE_USER_DETAILS_SUCCESS: "UPDATE_USER_DETAILS_SUCCESS",
SET_SHOP_DETAILS: "SET_SHOP_DETAILS"
}; };
export default UserActionTypes; export default UserActionTypes;

View File

@@ -35,6 +35,11 @@
"actions": "Actions" "actions": "Actions"
} }
}, },
"bodyshop": {
"errors": {
"loading": "Unable to load shop details. Please call technical support."
}
},
"documents": { "documents": {
"errors": { "errors": {
"deletes3": "Error deleting document from storage. ", "deletes3": "Error deleting document from storage. ",
@@ -87,6 +92,7 @@
"actions": { "actions": {
"addDocuments": "Add Job Documents", "addDocuments": "Add Job Documents",
"addNote": "Add Note", "addNote": "Add Note",
"changestatus": "Change Status",
"convert": "Convert", "convert": "Convert",
"postInvoices": "Post Invoices", "postInvoices": "Post Invoices",
"printCenter": "Print Center", "printCenter": "Print Center",

View File

@@ -35,6 +35,11 @@
"actions": "Comportamiento" "actions": "Comportamiento"
} }
}, },
"bodyshop": {
"errors": {
"loading": "No se pueden cargar los detalles de la tienda. Por favor llame al soporte técnico."
}
},
"documents": { "documents": {
"errors": { "errors": {
"deletes3": "Error al eliminar el documento del almacenamiento.", "deletes3": "Error al eliminar el documento del almacenamiento.",
@@ -87,6 +92,7 @@
"actions": { "actions": {
"addDocuments": "Agregar documentos de trabajo", "addDocuments": "Agregar documentos de trabajo",
"addNote": "Añadir la nota", "addNote": "Añadir la nota",
"changestatus": "Cambiar Estado",
"convert": "Convertir", "convert": "Convertir",
"postInvoices": "Contabilizar facturas", "postInvoices": "Contabilizar facturas",
"printCenter": "Centro de impresión", "printCenter": "Centro de impresión",

View File

@@ -35,6 +35,11 @@
"actions": "actes" "actions": "actes"
} }
}, },
"bodyshop": {
"errors": {
"loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique."
}
},
"documents": { "documents": {
"errors": { "errors": {
"deletes3": "Erreur lors de la suppression du document du stockage.", "deletes3": "Erreur lors de la suppression du document du stockage.",
@@ -87,6 +92,7 @@
"actions": { "actions": {
"addDocuments": "Ajouter des documents de travail", "addDocuments": "Ajouter des documents de travail",
"addNote": "Ajouter une note", "addNote": "Ajouter une note",
"changestatus": "Changer le statut",
"convert": "Convertir", "convert": "Convertir",
"postInvoices": "Poster des factures", "postInvoices": "Poster des factures",
"printCenter": "Centre d'impression", "printCenter": "Centre d'impression",