Added basic pages for template editing BOD-85
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.6.1">
|
<babeledit_project be_version="2.6.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -12546,6 +12546,63 @@
|
|||||||
</folder_node>
|
</folder_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<folder_node>
|
||||||
|
<name>templates</name>
|
||||||
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>errors</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>updating</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>
|
||||||
|
<folder_node>
|
||||||
|
<name>successes</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>updated</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>timetickets</name>
|
<name>timetickets</name>
|
||||||
<children>
|
<children>
|
||||||
@@ -13202,6 +13259,48 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>shop</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>
|
||||||
|
<name>shop-templates</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>vehicle-details</name>
|
<name>vehicle-details</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -13666,6 +13765,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>shop-templates</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>shop_vendors</name>
|
<name>shop_vendors</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import axios from "axios";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { EmailSettings } from "../../emails/constants";
|
import { EmailSettings } from "../../utils/constants";
|
||||||
import {
|
import {
|
||||||
endLoading,
|
endLoading,
|
||||||
startLoading,
|
startLoading,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { EmailSettings } from "../../emails/constants";
|
import { EmailSettings } from "../../utils/constants";
|
||||||
import { toggleEmailOverlayVisible } from "../../redux/email/email.actions";
|
import { toggleEmailOverlayVisible } from "../../redux/email/email.actions";
|
||||||
import {
|
import {
|
||||||
selectEmailConfig,
|
selectEmailConfig,
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Button, notification } from "antd";
|
||||||
|
import { useMutation } from "@apollo/react-hooks";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { UPDATE_TEMPLATE } from "../../graphql/templates.queries";
|
||||||
|
|
||||||
|
export default function ShopTemplateSaveButton({ templateId, html, gql }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [updateTemplate] = useMutation(UPDATE_TEMPLATE);
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
const result = await updateTemplate({
|
||||||
|
variables: {
|
||||||
|
templateId: templateId,
|
||||||
|
template: { query: gql, html },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!!!result.errors) {
|
||||||
|
notification["success"]({ message: t("templates.successes.updated") });
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("templates.errors.updating", {
|
||||||
|
error: JSON.stringify(result.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button disabled={!!!templateId} onClick={handleSave}>
|
||||||
|
{t("general.actions.save")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { Editor } from "@tinymce/tinymce-react";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import ShopTemplateEditorSaveButton from "../shop-template-editor-save-button/shop-template-editor-save-button.component";
|
||||||
|
|
||||||
|
export default function ShopTemplateEditorComponent({
|
||||||
|
templateId,
|
||||||
|
html,
|
||||||
|
gql,
|
||||||
|
editorState,
|
||||||
|
}) {
|
||||||
|
const [editorContent, seteditorContent] = editorState;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("HTML UE");
|
||||||
|
seteditorContent((prevstate) => {
|
||||||
|
return { ...prevstate, html: html };
|
||||||
|
});
|
||||||
|
}, [html, seteditorContent]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("gql UE");
|
||||||
|
seteditorContent((prevstate) => {
|
||||||
|
return { ...prevstate, gql: gql };
|
||||||
|
});
|
||||||
|
}, [gql, seteditorContent]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Editor Here. template Editor
|
||||||
|
<ShopTemplateEditorSaveButton
|
||||||
|
templateId={templateId}
|
||||||
|
html={editorContent.html}
|
||||||
|
gql={editorContent.gql}
|
||||||
|
/>
|
||||||
|
TEMPLATE
|
||||||
|
<Editor
|
||||||
|
value={editorContent.html}
|
||||||
|
apiKey='f3s2mjsd77ya5qvqkee9vgh612cm6h41e85efqakn2d0kknk' //TODO Pull this into app var
|
||||||
|
init={{
|
||||||
|
height: 500,
|
||||||
|
//menubar: false,
|
||||||
|
encoding: "raw",
|
||||||
|
extended_valid_elements: "span",
|
||||||
|
//entity_encoding: "raw",
|
||||||
|
plugins: [
|
||||||
|
"advlist autolink lists link image charmap print preview anchor",
|
||||||
|
"searchreplace visualblocks code fullscreen",
|
||||||
|
"insertdatetime media table paste code help wordcount",
|
||||||
|
],
|
||||||
|
toolbar:
|
||||||
|
"undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help",
|
||||||
|
}}
|
||||||
|
onEditorChange={(text) =>
|
||||||
|
seteditorContent({ ...editorContent, html: text })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
QUERY
|
||||||
|
<Editor
|
||||||
|
value={editorContent.gql}
|
||||||
|
apiKey='f3s2mjsd77ya5qvqkee9vgh612cm6h41e85efqakn2d0kknk' //TODO Pull this into app var
|
||||||
|
init={{
|
||||||
|
height: 500,
|
||||||
|
//menubar: false,
|
||||||
|
encoding: "raw",
|
||||||
|
extended_valid_elements: "span",
|
||||||
|
//entity_encoding: "raw",
|
||||||
|
plugins: [],
|
||||||
|
toolbar: "undo redo",
|
||||||
|
}}
|
||||||
|
onEditorChange={(text) =>
|
||||||
|
seteditorContent({ ...editorContent, gql: text })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <GraphiQL
|
||||||
|
// fetcher={async (graphQLParams) => {
|
||||||
|
// const data = await fetch(process.env.REACT_APP_GRAPHQL_ENDPOINT, {
|
||||||
|
// method: "POST",
|
||||||
|
// headers: {
|
||||||
|
// Accept: "application/json",
|
||||||
|
// "Content-Type": "application/json",
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify(graphQLParams),
|
||||||
|
// credentials: "same-origin",
|
||||||
|
// });
|
||||||
|
// return data.json().catch(() => data.text());
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
|
import queryString from "query-string";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
import { QUERY_TEMPLATE_BY_PK } from "../../graphql/templates.queries";
|
||||||
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
|
import ShopTemplateEditorComponent from "./shop-template-editor.component";
|
||||||
|
|
||||||
|
export default function ShopTemplateEditorContainer() {
|
||||||
|
const search = queryString.parse(useLocation().search);
|
||||||
|
const editorState = useState({ html: "", gql: "" });
|
||||||
|
|
||||||
|
const { loading, error, data } = useQuery(QUERY_TEMPLATE_BY_PK, {
|
||||||
|
variables: {
|
||||||
|
templateId: search.customTemplateId,
|
||||||
|
},
|
||||||
|
skip: !!!search.customTemplateId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!!!search.customTemplateId) return <span>No selection.</span>;
|
||||||
|
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingSpinner loading={loading}>
|
||||||
|
<ShopTemplateEditorComponent
|
||||||
|
templateId={search.customTemplateId}
|
||||||
|
html={data ? data.templates_by_pk.html : ""}
|
||||||
|
gql={data ? data.templates_by_pk.query : ""}
|
||||||
|
editorState={editorState}
|
||||||
|
/>
|
||||||
|
</LoadingSpinner>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
|
import { List, Button } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { QUERY_CUSTOM_TEMPLATES } from "../../graphql/templates.queries";
|
||||||
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import Skeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
|
import queryString from "query-string";
|
||||||
|
|
||||||
|
export default function ShopTemplatesListContainer() {
|
||||||
|
const { loading, error, data } = useQuery(QUERY_CUSTOM_TEMPLATES);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const search = queryString.parse(useLocation().search);
|
||||||
|
const history = useHistory();
|
||||||
|
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||||
|
|
||||||
|
const handleEdit = (record) => {
|
||||||
|
if (record) {
|
||||||
|
if (record.id) {
|
||||||
|
search.customTemplateId = record.id;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete search.customTemplateId;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>CUSTOM TEMPLATES</div>
|
||||||
|
<List
|
||||||
|
loading={loading}
|
||||||
|
itemLayout='horizontal'
|
||||||
|
dataSource={data ? data.templates : []}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item
|
||||||
|
actions={[
|
||||||
|
<Button onClick={() => handleEdit(item)}>
|
||||||
|
{t("general.actions.edit")}
|
||||||
|
</Button>,
|
||||||
|
<Button>{t("general.actions.delete")}</Button>,
|
||||||
|
]}>
|
||||||
|
<Skeleton title={false} loading={item.loading} active>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={item.name}
|
||||||
|
description='TODO CROSS MATCH DESCRIPTION'
|
||||||
|
/>
|
||||||
|
</Skeleton>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import gql from "graphql-tag";
|
|
||||||
|
|
||||||
export const shopAttributes = gql`
|
|
||||||
fragment shopData on query_root {
|
|
||||||
bodyshops(where: { associations: { active: { _eq: true } } }) {
|
|
||||||
id
|
|
||||||
address1
|
|
||||||
address2
|
|
||||||
city
|
|
||||||
email
|
|
||||||
federal_tax_id
|
|
||||||
state
|
|
||||||
shopname
|
|
||||||
zip_post
|
|
||||||
logo_img_path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function Header({ bodyshop }) {
|
|
||||||
return (
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img alt="" src={bodyshop.logo_img_path} />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div>
|
|
||||||
<strong>{`${bodyshop.shopname}`}</strong>
|
|
||||||
</div>
|
|
||||||
<div>{`${bodyshop.address1} ${bodyshop.address2} ${bodyshop.city} ${bodyshop.state} ${bodyshop.zip_post}`}</div>
|
|
||||||
<div>
|
|
||||||
<a href={`mailto:${bodyshop.email}`}>{bodyshop.email}</a>
|
|
||||||
{` | ${bodyshop.ph1}`}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import gql from "graphql-tag";
|
|
||||||
import { shopAttributes } from "../../components/fragments.queries";
|
|
||||||
|
|
||||||
export const EMAIL_APPOINTMENT_CONFIRMATION = gql`
|
|
||||||
query EMAIL_APPOINTMENT_CONFIRMATION($id: uuid!) {
|
|
||||||
appointments_by_pk(id: $id) {
|
|
||||||
start
|
|
||||||
title
|
|
||||||
job {
|
|
||||||
ownr_fn
|
|
||||||
ownr_ln
|
|
||||||
ownr_ea
|
|
||||||
}
|
|
||||||
}
|
|
||||||
...shopData
|
|
||||||
}
|
|
||||||
${shopAttributes}
|
|
||||||
`;
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import Header from "../../components/header/header.component";
|
|
||||||
import { DateTimeFormatter } from "../../../utils/DateFormatter";
|
|
||||||
|
|
||||||
const D = styled.div`
|
|
||||||
table {
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
border: 1px solid #dddddd;
|
|
||||||
text-align: left;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:nth-child(even) {
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Subject = "Appointment Reminder";
|
|
||||||
|
|
||||||
export default function AppointmentConfirmationEmail({ data }) {
|
|
||||||
const appointment = data.appointments_by_pk;
|
|
||||||
console.log("appointment", appointment);
|
|
||||||
return (
|
|
||||||
<D>
|
|
||||||
<Header bodyshop={data.bodyshops[0]} />
|
|
||||||
<strong>Appointment Reminder</strong>
|
|
||||||
<p> Dear {`${appointment.job.ownr_fn} ${appointment.job.ownr_ln}`},</p>
|
|
||||||
<p>
|
|
||||||
You have an appointment at {data.bodyshops[0].shopname} on
|
|
||||||
<DateTimeFormatter>{appointment.start}</DateTimeFormatter>.
|
|
||||||
</p>
|
|
||||||
<p>Thank you from the team at {data.bodyshops[0].shopname}</p>
|
|
||||||
</D>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import Header from "../../components/header/header.component";
|
|
||||||
|
|
||||||
const D = styled.div`
|
|
||||||
table {
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
border: 1px solid #dddddd;
|
|
||||||
text-align: left;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:nth-child(even) {
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function PartsOrderEmail({ data }) {
|
|
||||||
const order = data.parts_orders_by_pk;
|
|
||||||
return (
|
|
||||||
<D>
|
|
||||||
<Header bodyshop={data.bodyshops[0]} />
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>{`Deliver By: ${order.deliver_by}`}</td>
|
|
||||||
<td>{`Ordered By: ${order.user_email}`}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Line Description</th>
|
|
||||||
<th>Part #</th>
|
|
||||||
<th>Price</th>
|
|
||||||
<th>Line Remarks</th>
|
|
||||||
</tr>
|
|
||||||
{order.parts_order_lines.map(item => (
|
|
||||||
<tr key={item.id}>
|
|
||||||
<td>{item.line_desc}</td>
|
|
||||||
<td>{item.oem_partno}</td>
|
|
||||||
<td>{item.act_price}</td>
|
|
||||||
<td>{item.line_remarks}</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</table>
|
|
||||||
</D>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import gql from "graphql-tag";
|
|
||||||
import { shopAttributes } from "../../components/fragments.queries";
|
|
||||||
|
|
||||||
export const REPORT_QUERY_PARTS_ORDER_BY_PK = gql`
|
|
||||||
query REPORT_QUERY_PARTS_ORDER_BY_PK($id: uuid!) {
|
|
||||||
parts_orders_by_pk(id: $id) {
|
|
||||||
job {
|
|
||||||
id
|
|
||||||
vehicle {
|
|
||||||
id
|
|
||||||
v_model_desc
|
|
||||||
v_make_desc
|
|
||||||
v_model_yr
|
|
||||||
v_vin
|
|
||||||
}
|
|
||||||
ro_number
|
|
||||||
est_number
|
|
||||||
}
|
|
||||||
id
|
|
||||||
deliver_by
|
|
||||||
parts_order_lines {
|
|
||||||
id
|
|
||||||
db_price
|
|
||||||
act_price
|
|
||||||
line_desc
|
|
||||||
line_remarks
|
|
||||||
oem_partno
|
|
||||||
status
|
|
||||||
}
|
|
||||||
status
|
|
||||||
user_email
|
|
||||||
}
|
|
||||||
...shopData
|
|
||||||
}
|
|
||||||
${shopAttributes}
|
|
||||||
`;
|
|
||||||
@@ -11,3 +11,34 @@ export const QUERY_TEMPLATES_BY_NAME = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const QUERY_CUSTOM_TEMPLATES = gql`
|
||||||
|
query QUERY_CUSTOM_TEMPLATES {
|
||||||
|
templates(where: { bodyshopid: { _is_null: false } }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const QUERY_TEMPLATE_BY_PK = gql`
|
||||||
|
query QUERY_TEMPLATE_BY_PK($templateId: uuid!) {
|
||||||
|
templates_by_pk(id: $templateId) {
|
||||||
|
id
|
||||||
|
query
|
||||||
|
html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const UPDATE_TEMPLATE = gql`
|
||||||
|
mutation UPDATE_TEMPLATE(
|
||||||
|
$templateId: uuid!
|
||||||
|
$template: templates_set_input!
|
||||||
|
) {
|
||||||
|
update_templates(where: { id: { _eq: $templateId } }, _set: $template) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ import { BackTop, Layout } 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";
|
||||||
import { Route, Switch } from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
|
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
|
||||||
|
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
|
||||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||||
|
import FcmNotification from "../../components/fcm-notification/fcm-notification.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";
|
||||||
import "./manage.page.styles.scss";
|
|
||||||
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
|
|
||||||
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
||||||
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
|
import "./manage.page.styles.scss";
|
||||||
import FcmNotification from "../../components/fcm-notification/fcm-notification.component";
|
|
||||||
const ManageRootPage = lazy(() =>
|
const ManageRootPage = lazy(() =>
|
||||||
import("../manage-root/manage-root.page.container")
|
import("../manage-root/manage-root.page.container")
|
||||||
);
|
);
|
||||||
@@ -82,6 +82,9 @@ const ProductionListPage = lazy(() =>
|
|||||||
const ProductionBoardPage = lazy(() =>
|
const ProductionBoardPage = lazy(() =>
|
||||||
import("../production-board/production-board.container")
|
import("../production-board/production-board.container")
|
||||||
);
|
);
|
||||||
|
const ShopTemplates = lazy(() =>
|
||||||
|
import("../shop-templates/shop-templates.container")
|
||||||
|
);
|
||||||
const { Header, Content, Footer } = Layout;
|
const { Header, Content, Footer } = Layout;
|
||||||
|
|
||||||
export default function Manage({ match }) {
|
export default function Manage({ match }) {
|
||||||
@@ -218,6 +221,11 @@ export default function Manage({ match }) {
|
|||||||
component={JobsAvailablePage}
|
component={JobsAvailablePage}
|
||||||
/>
|
/>
|
||||||
<Route exact path={`${match.path}/shop/`} component={ShopPage} />
|
<Route exact path={`${match.path}/shop/`} component={ShopPage} />
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`${match.path}/shop/templates`}
|
||||||
|
component={ShopTemplates}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path={`${match.path}/shop/vendors`}
|
path={`${match.path}/shop/vendors`}
|
||||||
|
|||||||
41
client/src/pages/shop-templates/shop-templates.container.js
Normal file
41
client/src/pages/shop-templates/shop-templates.container.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { setBreadcrumbs } from "../../redux/application/application.actions";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import ShopTemplatesListContainer from "../../components/shop-templates-list/shop-templates-list.container";
|
||||||
|
import ShopTemplateEditor from "../../components/shop-template-editor/shop-template-editor.container";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export function ShopTemplatesContainer({ setBreadcrumbs, bodyshop }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = t("titles.shop-templates");
|
||||||
|
setBreadcrumbs([
|
||||||
|
{
|
||||||
|
link: "/manage/shop",
|
||||||
|
label: t("titles.bc.shop", { shopname: bodyshop.shopname }),
|
||||||
|
},
|
||||||
|
{ link: "/manage/shop/templates", label: t("titles.bc.shop-templates") },
|
||||||
|
]);
|
||||||
|
}, [t, setBreadcrumbs, bodyshop.shopname]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ShopTemplatesListContainer />
|
||||||
|
<ShopTemplateEditor />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ShopTemplatesContainer);
|
||||||
@@ -808,6 +808,14 @@
|
|||||||
"state": "Error reading page state. Please refresh."
|
"state": "Error reading page state. Please refresh."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"templates": {
|
||||||
|
"errors": {
|
||||||
|
"updating": "Error updating template {{error}}."
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"updated": "Template updated successfully."
|
||||||
|
}
|
||||||
|
},
|
||||||
"timetickets": {
|
"timetickets": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"enter": "Enter New Time Ticket"
|
"enter": "Enter New Time Ticket"
|
||||||
@@ -848,6 +856,8 @@
|
|||||||
"productionboard": "Production Board",
|
"productionboard": "Production Board",
|
||||||
"productionlist": "Production - List",
|
"productionlist": "Production - List",
|
||||||
"schedule": "Schedule",
|
"schedule": "Schedule",
|
||||||
|
"shop": "Manage my Shop ({{shopname}})",
|
||||||
|
"shop-templates": "Shop Templates",
|
||||||
"vehicle-details": "Vehicle: {{vehicle}}",
|
"vehicle-details": "Vehicle: {{vehicle}}",
|
||||||
"vehicles": "Vehicles"
|
"vehicles": "Vehicles"
|
||||||
},
|
},
|
||||||
@@ -871,6 +881,7 @@
|
|||||||
"profile": "My Profile | $t(titles.app)",
|
"profile": "My Profile | $t(titles.app)",
|
||||||
"schedule": "Schedule | $t(titles.app)",
|
"schedule": "Schedule | $t(titles.app)",
|
||||||
"shop": "My Shop | $t(titles.app)",
|
"shop": "My Shop | $t(titles.app)",
|
||||||
|
"shop-templates": "Shop Templates | $t(titles.app)",
|
||||||
"shop_vendors": "Vendors | $t(titles.app)",
|
"shop_vendors": "Vendors | $t(titles.app)",
|
||||||
"vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)",
|
"vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)",
|
||||||
"vehicles": "All Vehicles | $t(titles.app)"
|
"vehicles": "All Vehicles | $t(titles.app)"
|
||||||
|
|||||||
@@ -808,6 +808,14 @@
|
|||||||
"state": "Error al leer el estado de la página. Porfavor refresca."
|
"state": "Error al leer el estado de la página. Porfavor refresca."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"templates": {
|
||||||
|
"errors": {
|
||||||
|
"updating": ""
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"updated": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"timetickets": {
|
"timetickets": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"enter": ""
|
"enter": ""
|
||||||
@@ -848,6 +856,8 @@
|
|||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
"productionlist": "",
|
"productionlist": "",
|
||||||
"schedule": "",
|
"schedule": "",
|
||||||
|
"shop": "",
|
||||||
|
"shop-templates": "",
|
||||||
"vehicle-details": "",
|
"vehicle-details": "",
|
||||||
"vehicles": ""
|
"vehicles": ""
|
||||||
},
|
},
|
||||||
@@ -871,6 +881,7 @@
|
|||||||
"profile": "Mi perfil | $t(titles.app)",
|
"profile": "Mi perfil | $t(titles.app)",
|
||||||
"schedule": "Horario | $t(titles.app)",
|
"schedule": "Horario | $t(titles.app)",
|
||||||
"shop": "Mi tienda | $t(titles.app)",
|
"shop": "Mi tienda | $t(titles.app)",
|
||||||
|
"shop-templates": "",
|
||||||
"shop_vendors": "Vendedores | $t(titles.app)",
|
"shop_vendors": "Vendedores | $t(titles.app)",
|
||||||
"vehicledetail": "Detalles del vehículo {{vehicle}} | $t(titles.app)",
|
"vehicledetail": "Detalles del vehículo {{vehicle}} | $t(titles.app)",
|
||||||
"vehicles": "Todos los vehiculos | $t(titles.app)"
|
"vehicles": "Todos los vehiculos | $t(titles.app)"
|
||||||
|
|||||||
@@ -808,6 +808,14 @@
|
|||||||
"state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait."
|
"state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"templates": {
|
||||||
|
"errors": {
|
||||||
|
"updating": ""
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"updated": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"timetickets": {
|
"timetickets": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"enter": ""
|
"enter": ""
|
||||||
@@ -848,6 +856,8 @@
|
|||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
"productionlist": "",
|
"productionlist": "",
|
||||||
"schedule": "",
|
"schedule": "",
|
||||||
|
"shop": "",
|
||||||
|
"shop-templates": "",
|
||||||
"vehicle-details": "",
|
"vehicle-details": "",
|
||||||
"vehicles": ""
|
"vehicles": ""
|
||||||
},
|
},
|
||||||
@@ -871,6 +881,7 @@
|
|||||||
"profile": "Mon profil | $t(titles.app)",
|
"profile": "Mon profil | $t(titles.app)",
|
||||||
"schedule": "Horaire | $t(titles.app)",
|
"schedule": "Horaire | $t(titles.app)",
|
||||||
"shop": "Mon magasin | $t(titles.app)",
|
"shop": "Mon magasin | $t(titles.app)",
|
||||||
|
"shop-templates": "",
|
||||||
"shop_vendors": "Vendeurs | $t(titles.app)",
|
"shop_vendors": "Vendeurs | $t(titles.app)",
|
||||||
"vehicledetail": "Détails du véhicule {{vehicle} | $t(titles.app)",
|
"vehicledetail": "Détails du véhicule {{vehicle} | $t(titles.app)",
|
||||||
"vehicles": "Tous les véhicules | $t(titles.app)"
|
"vehicles": "Tous les véhicules | $t(titles.app)"
|
||||||
|
|||||||
Reference in New Issue
Block a user