diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 9d9639c53..84a926025 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1975,6 +1975,488 @@ + + courtesycars + + + erorrs + + + saving + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + fields + + + color + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + dailycost + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + damage + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fleetnumber + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fuel + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + insuranceexpires + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + leaseenddate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + make + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + model + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + nextservicedate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + nextservicekm + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + notes + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + plate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + purchasedate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + registrationexpires + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + serviceenddate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + servicestartdate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + status + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + vin + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + year + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + successes + + + saved + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + documents @@ -7409,6 +7891,90 @@ + + courtesycars + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + courtesycars-all + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + courtesycars-contracts + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + courtesycars-newcontract + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + customers false @@ -8964,6 +9530,27 @@ + + courtesycars-create + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + jobs false @@ -8985,6 +9572,27 @@ + + jobs-create + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + jobsavailable false diff --git a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx new file mode 100644 index 000000000..a226feb48 --- /dev/null +++ b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx @@ -0,0 +1,197 @@ +import React from "react"; +import { Form, Input, InputNumber, DatePicker, Button } from "antd"; +import { useTranslation } from "react-i18next"; +import CurrencyInput from "../form-items-formatted/currency-form-item.component"; +export default function CourtesyCarCreateFormComponent() { + const { t } = useTranslation(); + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); +} diff --git a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx new file mode 100644 index 000000000..bf7e57dff --- /dev/null +++ b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx @@ -0,0 +1,82 @@ +import { Table } from "antd"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import { alphaSort } from "../../utils/sorters"; + +export default function JobsList({ loading, courtesycars }) { + const [state, setState] = useState({ + sortedInfo: {}, + filteredInfo: { text: "" } + }); + console.log("courtesycars", courtesycars); + + const { t } = useTranslation(); + + const columns = [ + { + title: t("courtesycars.fields.fleetnumber"), + dataIndex: "fleetnumber", + key: "fleetnumber", + sorter: (a, b) => alphaSort(a.fleetnumber, b.fleetnumber), + sortOrder: + state.sortedInfo.columnKey === "fleetnumber" && state.sortedInfo.order + }, + { + title: t("courtesycars.fields.vin"), + dataIndex: "vin", + key: "vin", + sorter: (a, b) => alphaSort(a.vin, b.vin), + sortOrder: state.sortedInfo.columnKey === "vin" && state.sortedInfo.order, + render: (text, record) => ( + {record.vin} + ) + }, + { + title: t("courtesycars.fields.status"), + dataIndex: "status", + key: "status", + sorter: (a, b) => alphaSort(a.status, b.status), + sortOrder: + state.sortedInfo.columnKey === "status" && state.sortedInfo.order + }, + { + title: t("courtesycars.fields.year"), + dataIndex: "year", + key: "year", + sorter: (a, b) => alphaSort(a.year, b.year), + sortOrder: state.sortedInfo.columnKey === "year" && state.sortedInfo.order + }, + { + title: t("courtesycars.fields.make"), + dataIndex: "make", + key: "make", + sorter: (a, b) => alphaSort(a.make, b.make), + sortOrder: state.sortedInfo.columnKey === "make" && state.sortedInfo.order + }, + { + title: t("courtesycars.fields.model"), + dataIndex: "model", + key: "model", + sorter: (a, b) => alphaSort(a.model, b.model), + sortOrder: + state.sortedInfo.columnKey === "model" && state.sortedInfo.order + } + ]; + + const handleTableChange = (pagination, filters, sorter) => { + setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); + }; + + return ( + ({ ...item }))} + rowKey="id" + dataSource={courtesycars} + onChange={handleTableChange} + /> + ); +} diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 4624cc600..d8b8dd4c5 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -1,4 +1,12 @@ -import { CalendarFilled, CarFilled, GlobalOutlined, HomeFilled, TeamOutlined } from "@ant-design/icons"; +import { + CalendarFilled, + CarFilled, + GlobalOutlined, + HomeFilled, + TeamOutlined, + FileAddFilled, + FileFilled +} from "@ant-design/icons"; import { Avatar, Col, Menu, Row } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -122,6 +130,28 @@ export default ({ + + + + + + {t("menus.header.courtesycars-all")} + + + + + + {t("menus.header.courtesycars-contracts")} + + + + + + {t("menus.header.courtesycars-newcontract")} + + + + {t("menus.header.shop_config")} diff --git a/client/src/graphql/courtesy-car.queries.js b/client/src/graphql/courtesy-car.queries.js new file mode 100644 index 000000000..1457d5b7a --- /dev/null +++ b/client/src/graphql/courtesy-car.queries.js @@ -0,0 +1,82 @@ +import { gql } from "apollo-boost"; + +export const INSERT_NEW_COURTESY_CAR = gql` + mutation INSERT_NEW_COURTESY_CAR( + $courtesycar: [courtesycars_insert_input!]! + ) { + insert_courtesycars(objects: $courtesycar) { + returning { + id + } + } + } +`; + +export const QUERY_ALL_CC = gql` + query QUERY_ALL_CC { + courtesycars { + color + created_at + dailycost + damage + fleetnumber + fuel + id + insuranceexpires + leaseenddate + make + model + nextservicedate + nextservicekm + notes + plate + purchasedate + registrationexpires + serviceenddate + servicestartdate + status + vin + year + } + } +`; + +export const QUERY_CC_BY_PK = gql` + query QUERY_CC_BY_PK($id: uuid!) { + courtesycars_by_pk(id: $id) { + bodyshopid + color + created_at + dailycost + damage + fleetnumber + fuel + id + insuranceexpires + leaseenddate + make + model + nextservicedate + nextservicekm + notes + plate + purchasedate + registrationexpires + serviceenddate + servicestartdate + status + vin + year + } + } +`; + +export const UPDATE_CC = gql` + mutation UPDATE_CC($ccId: uuid!, $cc: courtesycars_set_input!) { + update_courtesycars(where: { id: { _eq: $ccId } }, _set: $cc) { + returning { + id + } + } + } +`; diff --git a/client/src/graphql/initial-state.js b/client/src/graphql/initial-state.js deleted file mode 100644 index fc69d4836..000000000 --- a/client/src/graphql/initial-state.js +++ /dev/null @@ -1,8 +0,0 @@ -export default { - __typename: "State", - currentUser: null, - selectedNavItem: "Home", - recentItems: [], - bodyShopData: null, - language: "en_us" -}; diff --git a/client/src/pages/courtesy-car-create/courtesy-car-create.page.component.jsx b/client/src/pages/courtesy-car-create/courtesy-car-create.page.component.jsx new file mode 100644 index 000000000..a9c15e7d3 --- /dev/null +++ b/client/src/pages/courtesy-car-create/courtesy-car-create.page.component.jsx @@ -0,0 +1,6 @@ +import React from "react"; +import CourtesyCarCreateFormComponent from "../../components/courtesy-car-form/courtesy-car-form.component" + +export default function CourtesyCarCreateComponent() { + return ; +} diff --git a/client/src/pages/courtesy-car-create/courtesy-car-create.page.container.jsx b/client/src/pages/courtesy-car-create/courtesy-car-create.page.container.jsx new file mode 100644 index 000000000..ef10bf592 --- /dev/null +++ b/client/src/pages/courtesy-car-create/courtesy-car-create.page.container.jsx @@ -0,0 +1,40 @@ +import { useMutation } from "@apollo/react-hooks"; +import { Form, notification } from "antd"; +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { INSERT_NEW_COURTESY_CAR } from "../../graphql/courtesy-car.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import CourtesyCarCreateComponent from "./courtesy-car-create.page.component"; + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop +}); + +export function CourtesyCarCreateContainer({ bodyshop }) { + const [form] = Form.useForm(); + const [insertCourtesyCar] = useMutation(INSERT_NEW_COURTESY_CAR); + const { t } = useTranslation(); + + const handleFinish = values => { + insertCourtesyCar({ + variables: { courtesycar: { ...values, bodyshopid: bodyshop.id } } + }) + .then(response => { + notification["success"]({ message: t("courtesycars.successes.saved") }); + }) + .catch(error => console.log("error", error)); + }; + + useEffect(() => { + document.title = t("titles.courtesycars-create"); + }, [t]); + + return ( +
+ + + ); +} +export default connect(mapStateToProps, null)(CourtesyCarCreateContainer); diff --git a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.component.jsx b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.component.jsx new file mode 100644 index 000000000..586e83b4c --- /dev/null +++ b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.component.jsx @@ -0,0 +1,6 @@ +import React from "react"; +import CourtesyCarCreateFormComponent from "../../components/courtesy-car-form/courtesy-car-form.component"; + +export default function CourtesyCarDetailPageComponent() { + return ; +} diff --git a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx new file mode 100644 index 000000000..e270cc192 --- /dev/null +++ b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx @@ -0,0 +1,87 @@ +import { useMutation, useQuery } from "@apollo/react-hooks"; +import { Form, notification } from "antd"; +import moment from "moment"; +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useParams } from "react-router-dom"; +import AlertComponent from "../../components/alert/alert.component"; +import { QUERY_CC_BY_PK, UPDATE_CC } from "../../graphql/courtesy-car.queries"; +import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component"; + +export default function CourtesyCarDetailPageContainer() { + const { t } = useTranslation(); + const [insertCourtesyCar] = useMutation(UPDATE_CC); + const [form] = Form.useForm(); + const { ccId } = useParams(); + + const { loading, error, data } = useQuery(QUERY_CC_BY_PK, { + variables: { id: ccId } + }); + + useEffect(() => { + document.title = loading + ? t("titles.app") + : error + ? t("titles.app") + : t("titles.courtesycars-detail", { + id: (data && data.courtesycars_by_pk.vin) || "" + }); + }, [t, data, error, loading]); + + const handleFinish = values => { + insertCourtesyCar({ + variables: { cc: { ...values }, ccId: ccId } + }) + .then(response => { + notification["success"]({ message: t("courtesycars.successes.saved") }); + }) + .catch(error => + notification["error"]({ + message: t("courtesycars.errors.saving", { error: error }) + }) + ); + }; + + useEffect(() => { + if (data) form.resetFields(); + }, [data, form]); + + if (error) return ; + return ( +
+ + + ); +} diff --git a/client/src/pages/courtesy-cars/courtesy-cars.page.component.jsx b/client/src/pages/courtesy-cars/courtesy-cars.page.component.jsx new file mode 100644 index 000000000..4d59ebc34 --- /dev/null +++ b/client/src/pages/courtesy-cars/courtesy-cars.page.component.jsx @@ -0,0 +1,6 @@ +import React from "react"; +import CourtesyCarsListComponent from "../../components/courtesy-cars-list/courtesy-cars-list.component"; + +export default function CourtesyCarsPageComponent({ loading, data }) { + return ; +} diff --git a/client/src/pages/courtesy-cars/courtesy-cars.page.container.jsx b/client/src/pages/courtesy-cars/courtesy-cars.page.container.jsx new file mode 100644 index 000000000..3aac89538 --- /dev/null +++ b/client/src/pages/courtesy-cars/courtesy-cars.page.container.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import CourtesyCarsPageComponent from "./courtesy-cars.page.component"; +import { useQuery } from "@apollo/react-hooks"; +import AlertComponent from "../../components/alert/alert.component"; +import { QUERY_ALL_CC } from "../../graphql/courtesy-car.queries"; + +export default function CourtesyCarsPageContainer() { + const { loading, error, data } = useQuery(QUERY_ALL_CC); + + if (error) return ; + return ( + + ); +} diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx index 2cf62ad6f..7132fa291 100644 --- a/client/src/pages/jobs-create/jobs-create.container.jsx +++ b/client/src/pages/jobs-create/jobs-create.container.jsx @@ -35,15 +35,17 @@ function JobsCreateContainer({ bodyshop }) { useEffect(() => { if (!!state.owner.selectedid) { - console.log("Loading Selected Owner ID"); loadOwner({ variables: { id: state.owner.selectedid } }); } }, [state.owner.selectedid, loadOwner]); + useEffect(() => { + document.title = t("titles.jobs-create"); + }, [t]); + const runInsertJob = job => { - console.log("Job To Save", job); insertJob({ variables: { job: job } }) .then(resp => { setState({ @@ -63,8 +65,6 @@ function JobsCreateContainer({ bodyshop }) { }; const handleFinish = values => { - console.log("Form Values", values); - console.log("Progress State", state); let job = Object.assign( {}, values, diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index 00b9ea5c3..842e03150 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -43,10 +43,18 @@ const ShopVendorPageContainer = lazy(() => const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx") ); - const JobsCreateContainerPage = lazy(() => import("../jobs-create/jobs-create.container") ); +const CourtesyCarCreateContainer = lazy(() => + import("../courtesy-car-create/courtesy-car-create.page.container") +); +const CourtesyCarDetailContainer = lazy(() => + import("../courtesy-car-detail/courtesy-car-detail.page.container") +); +const CourtesyCarsPage = lazy(() => + import("../courtesy-cars/courtesy-cars.page.container") +); const { Header, Content, Footer } = Layout; @@ -64,13 +72,15 @@ export default function Manage({ match }) { + className="content-container" + style={{ padding: "0em 4em 4em" }} + > - }> + } + > @@ -86,7 +96,41 @@ export default function Manage({ match }) { component={JobsDetailPage} /> + + + +
HOLD
} + /> + +
new cc contract
} + /> +
cc contract id
} + /> + + +