Added first round of analytics and event tracking BOD-190
This commit is contained in:
@@ -8,6 +8,7 @@ import InvoiceExportButton from "../invoice-export-button/invoice-export-button.
|
||||
import InvoiceExportAllButton from "../invoice-export-all-button/invoice-export-all-button.component";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import queryString from "query-string";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function AccountingPayablesTableComponent({
|
||||
loading,
|
||||
@@ -38,8 +39,7 @@ export default function AccountingPayablesTableComponent({
|
||||
to={{
|
||||
pathname: `/manage/shop/vendors`,
|
||||
search: queryString.stringify({ selectedvendor: record.vendor.id }),
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{record.vendor.name}
|
||||
</Link>
|
||||
),
|
||||
@@ -60,8 +60,7 @@ export default function AccountingPayablesTableComponent({
|
||||
invoiceid: record.id,
|
||||
vendorid: record.vendor.id,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{record.invoice_number}
|
||||
</Link>
|
||||
),
|
||||
@@ -131,6 +130,7 @@ export default function AccountingPayablesTableComponent({
|
||||
|
||||
const handleSearch = (e) => {
|
||||
setState({ ...state, search: e.target.value });
|
||||
logImEXEvent("accounting_payables_table_search");
|
||||
};
|
||||
|
||||
const dataSource = state.search
|
||||
@@ -168,10 +168,10 @@ export default function AccountingPayablesTableComponent({
|
||||
);
|
||||
}}
|
||||
dataSource={dataSource}
|
||||
size="small"
|
||||
size='small'
|
||||
pagination={{ position: "top", pageSize: 50 }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
onSelectAll: (selected, selectedRows) =>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import PaymentExportButton from "../payment-export-button/payment-export-button.component";
|
||||
import { PaymentsExportAllButton } from "../payments-export-all-button/payments-export-all-button.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function AccountingPayablesTableComponent({
|
||||
loading,
|
||||
@@ -129,6 +130,7 @@ export default function AccountingPayablesTableComponent({
|
||||
|
||||
const handleSearch = (e) => {
|
||||
setState({ ...state, search: e.target.value });
|
||||
logImEXEvent("account_payments_table_search");
|
||||
};
|
||||
|
||||
const dataSource = state.search
|
||||
@@ -166,10 +168,10 @@ export default function AccountingPayablesTableComponent({
|
||||
);
|
||||
}}
|
||||
dataSource={dataSource}
|
||||
size="small"
|
||||
size='small'
|
||||
pagination={{ position: "top", pageSize: 50 }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
onSelectAll: (selected, selectedRows) =>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Link } from "react-router-dom";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function AccountingReceivablesTableComponent({ loading, jobs }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -138,6 +139,7 @@ export default function AccountingReceivablesTableComponent({ loading, jobs }) {
|
||||
|
||||
const handleSearch = (e) => {
|
||||
setState({ ...state, search: e.target.value });
|
||||
logImEXEvent("accounting_receivables_search");
|
||||
};
|
||||
|
||||
const dataSource = state.search
|
||||
@@ -187,10 +189,10 @@ export default function AccountingReceivablesTableComponent({ loading, jobs }) {
|
||||
);
|
||||
}}
|
||||
dataSource={dataSource}
|
||||
size="small"
|
||||
size='small'
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Alert } from "antd";
|
||||
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import React from "react";
|
||||
|
||||
export default function AlertComponent(props) {
|
||||
if (props.type === "error") logImEXEvent("alert_render", { ...props });
|
||||
return <Alert {...props} />;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@ import AuditTrailListComponent from "./audit-trail-list.component";
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import { QUERY_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function AuditTrailListContainer({ recordId }) {
|
||||
const { loading, error, data } = useQuery(QUERY_AUDIT_TRAIL, {
|
||||
variables: { id: recordId },
|
||||
fetchPolicy: "network-only"
|
||||
fetchPolicy: "network-only",
|
||||
});
|
||||
|
||||
logImEXEvent("audittrail_view", { recordId });
|
||||
return (
|
||||
<div>
|
||||
{error ? (
|
||||
<AlertComponent type="error" message={error.message} />
|
||||
<AlertComponent type='error' message={error.message} />
|
||||
) : (
|
||||
<AuditTrailListComponent
|
||||
loading={loading}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Tag } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
export default function ChatConversationTitleTags({ jobConversations }) {
|
||||
const [removeJobConversation] = useMutation(REMOVE_CONVERSATION_TAG);
|
||||
|
||||
@@ -16,6 +16,10 @@ export default function ChatConversationTitleTags({ jobConversations }) {
|
||||
jobId: jobId,
|
||||
},
|
||||
});
|
||||
logImEXEvent("messaging_remove_job_tag", {
|
||||
conversationId: convId,
|
||||
jobId: jobId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,11 +39,7 @@ export function ChatConversationContainer({ selectedConversation }) {
|
||||
0;
|
||||
|
||||
const handleMarkConversationAsRead = async () => {
|
||||
if (
|
||||
unreadCount > 0 &&
|
||||
!!selectedConversation &&
|
||||
!markingAsReadInProgress
|
||||
) {
|
||||
if (unreadCount > 0 && !!selectedConversation && !markingAsReadInProgress) {
|
||||
setMarkingAsReadInProgress(true);
|
||||
await markConversationRead();
|
||||
setMarkingAsReadInProgress(false);
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { Input, Spin } from "antd";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Input, Spin } from "antd";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { sendMessage } from "../../redux/messaging/messaging.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { selectIsSending } from "../../redux/messaging/messaging.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
isSending: selectIsSending,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
sendMessage: (message) => dispatch(sendMessage(message)),
|
||||
});
|
||||
@@ -34,6 +36,7 @@ function ChatSendMessageComponent({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleEnter = () => {
|
||||
logImEXEvent("messaging_send_message");
|
||||
sendMessage({
|
||||
to: conversation.phone_num,
|
||||
body: message,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries
|
||||
import { Tag } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ChatTagRoContainer({ conversation }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -21,6 +22,7 @@ export default function ChatTagRoContainer({ conversation }) {
|
||||
);
|
||||
|
||||
const executeSearch = () => {
|
||||
logImEXEvent("messaging_search_job_tag", { searchTerm: searchText });
|
||||
if (called) refetch();
|
||||
else {
|
||||
loadRo();
|
||||
@@ -32,6 +34,7 @@ export default function ChatTagRoContainer({ conversation }) {
|
||||
});
|
||||
|
||||
const handleInsertTag = (value, option) => {
|
||||
logImEXEvent("messaging_add_job_tag");
|
||||
insertTag({ variables: { jobId: option.key } });
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
import aamva from "../../utils/aamva";
|
||||
import DataLabel from "../data-label/data-label.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ContractLicenseDecodeButton({ form }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -12,14 +13,19 @@ export default function ContractLicenseDecodeButton({ form }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [decodedBarcode, setDecodedBarcode] = useState(null);
|
||||
console.log("form", form);
|
||||
|
||||
const handleDecode = (e) => {
|
||||
logImEXEvent("contract_license_decode");
|
||||
setLoading(true);
|
||||
const aamvaParse = aamva.parse(e.currentTarget.value);
|
||||
console.log("AAMVA", aamvaParse);
|
||||
setDecodedBarcode(aamvaParse);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const handleInsertForm = () => {
|
||||
logImEXEvent("contract_license_decode_fill_form");
|
||||
|
||||
const values = {
|
||||
driver_dlnumber: decodedBarcode.dl,
|
||||
driver_dlexpiry: moment(
|
||||
@@ -55,8 +61,7 @@ export default function ContractLicenseDecodeButton({ form }) {
|
||||
okText={t("contracts.actions.senddltoform")}
|
||||
onOk={handleInsertForm}
|
||||
okButtonProps={{ disabled: !!!decodedBarcode }}
|
||||
onCancel={handleCancel}
|
||||
>
|
||||
onCancel={handleCancel}>
|
||||
<div>
|
||||
<div>
|
||||
<Input
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { MdClose } from "react-icons/md";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { QUERY_DASHBOARD_DETAILS } from "../../graphql/bodyshop.queries";
|
||||
import { UPDATE_DASHBOARD_LAYOUT } from "../../graphql/user.queries";
|
||||
import {
|
||||
@@ -37,6 +38,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
export function DashboardGridComponent({ currentUser, bodyshop }) {
|
||||
const { loading, error, data } = useQuery(QUERY_DASHBOARD_DETAILS);
|
||||
console.log("DashboardGridComponent -> data", data)
|
||||
const { t } = useTranslation();
|
||||
const [state, setState] = useState({
|
||||
layout: bodyshop.associations[0].user.dashboardlayout || [
|
||||
@@ -47,6 +49,7 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
|
||||
const [updateLayout] = useMutation(UPDATE_DASHBOARD_LAYOUT);
|
||||
|
||||
const handleLayoutChange = async (newLayout) => {
|
||||
logImEXEvent("dashboard_change_layout");
|
||||
setState({ ...state, layout: newLayout });
|
||||
const result = await updateLayout({
|
||||
variables: { email: currentUser.email, layout: newLayout },
|
||||
@@ -62,6 +65,8 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
|
||||
};
|
||||
|
||||
const handleRemoveComponent = (key) => {
|
||||
logImEXEvent("dashboard_remove_component", { name: key });
|
||||
|
||||
const idxToRemove = state.layout.findIndex((i) => i.i === key);
|
||||
const newLayout = state.layout;
|
||||
newLayout.splice(idxToRemove, 1);
|
||||
@@ -70,6 +75,8 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
|
||||
};
|
||||
|
||||
const handleAddComponent = (e) => {
|
||||
logImEXEvent("dashboard_add_component", { name: e });
|
||||
|
||||
handleLayoutChange([
|
||||
...state.layout,
|
||||
{
|
||||
@@ -99,7 +106,6 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
|
||||
))}
|
||||
</Menu>
|
||||
);
|
||||
console.log("Dashboard Data:", data);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@ import Resizer from "react-image-file-resizer";
|
||||
import { client } from "../../App/App.container";
|
||||
import { INSERT_NEW_DOCUMENT } from "../../graphql/documents.queries";
|
||||
import i18n from "i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
//Context: currentUserEmail, bodyshop, jobid, invoiceid
|
||||
export const handleUpload = (ev, context) => {
|
||||
console.log("ev", ev);
|
||||
|
||||
logImEXEvent("document_upload", { filetype: ev.file.type });
|
||||
|
||||
const { onError, onSuccess, onProgress } = ev;
|
||||
const { bodyshop, jobId } = context;
|
||||
//If PDF, upload directly.
|
||||
|
||||
@@ -14,6 +14,7 @@ import { EmailSettings } from "../../utils/TemplateConstants";
|
||||
import RenderTemplate from "../../utils/RenderTemplate";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import EmailOverlayComponent from "./email-overlay.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
modalVisible: selectEmailVisible,
|
||||
@@ -47,6 +48,8 @@ export function EmailOverlayContainer({
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
logImEXEvent("email_send_from_modal");
|
||||
|
||||
setSending(true);
|
||||
try {
|
||||
await axios.post("/sendemail", messageOptions);
|
||||
@@ -70,6 +73,8 @@ export function EmailOverlayContainer({
|
||||
};
|
||||
|
||||
const render = async () => {
|
||||
logImEXEvent("email_render_template", { template: emailConfig.template });
|
||||
|
||||
setLoading(true);
|
||||
console.log("emailConfig", emailConfig);
|
||||
let html = await RenderTemplate(emailConfig.template, bodyshop);
|
||||
@@ -94,8 +99,7 @@ export function EmailOverlayContainer({
|
||||
onCancel={() => {
|
||||
toggleEmailOverlayVisible();
|
||||
}}
|
||||
okButtonProps={{ loading: sending }}
|
||||
>
|
||||
okButtonProps={{ loading: sending }}>
|
||||
<LoadingSpinner loading={loading}>
|
||||
<EmailOverlayComponent
|
||||
handleConfigChange={handleConfigChange}
|
||||
@@ -105,8 +109,7 @@ export function EmailOverlayContainer({
|
||||
<button
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(messageOptions.html);
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
Copy HTML
|
||||
</button>
|
||||
</LoadingSpinner>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Button, Col, Collapse, Result, Row, Space } from "antd";
|
||||
import React from "react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { Result, Button, Collapse, Row, Col, Space } from "antd";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor() {
|
||||
@@ -24,28 +25,29 @@ class ErrorBoundary extends React.Component {
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { error, info } = this.state;
|
||||
if (this.state.hasErrored === true) {
|
||||
logImEXEvent("error_boundary_rendered", { error, info });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Result
|
||||
status="500"
|
||||
status='500'
|
||||
title={t("general.labels.exceptiontitle")}
|
||||
subTitle={t("general.messages.exception")}
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("general.actions.refresh")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
alert("Not implemented yet.");
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("general.actions.submitticket")}
|
||||
</Button>
|
||||
</Space>
|
||||
|
||||
@@ -2,9 +2,10 @@ import React, { Component } from "react";
|
||||
import { withApollo } from "react-apollo";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { messaging } from "../../firebase/firebase.utils";
|
||||
import { logImEXEvent, messaging } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_FCM_TOKEN } from "../../graphql/user.queries";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
@@ -28,6 +29,7 @@ class FcmNotificationComponent extends Component {
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log("Unable to get permission to notify.", err);
|
||||
logImEXEvent("fcm_permission_denied", { message: err });
|
||||
});
|
||||
navigator.serviceWorker.addEventListener("message", (message) => {
|
||||
const { payload } = message.data.firebaseMessaging;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { useLazyQuery } from "@apollo/react-hooks";
|
||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||
import { Input, AutoComplete } from "antd";
|
||||
import { AutoComplete, Input } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { Link } from "react-router-dom";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
export default function GlobalSearch() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -13,6 +15,8 @@ export default function GlobalSearch() {
|
||||
);
|
||||
|
||||
const handleSearch = (searchTerm) => {
|
||||
logImEXEvent("global_search", { term: searchTerm });
|
||||
|
||||
if (searchTerm.length > 0)
|
||||
callSearch({ variables: { search: searchTerm } });
|
||||
};
|
||||
@@ -129,6 +133,8 @@ export default function GlobalSearch() {
|
||||
]
|
||||
: [];
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AutoComplete
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { setUserLanguage } from "../../redux/user/user.actions";
|
||||
import HeaderComponent from "./header.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setUserLanguage: (language) => dispatch(setUserLanguage(language)),
|
||||
@@ -12,8 +13,13 @@ export function HeaderContainer({ setUserLanguage }) {
|
||||
const handleMenuClick = (e) => {
|
||||
if (e.item.props.actiontype === "lang-select") {
|
||||
i18next.changeLanguage(e.key, (err, t) => {
|
||||
if (err)
|
||||
if (err) {
|
||||
logImEXEvent("language_change_error", { error: err });
|
||||
|
||||
return console.log("Error encountered when changing languages.", err);
|
||||
}
|
||||
logImEXEvent("language_change", { language: e.key });
|
||||
|
||||
setUserLanguage(e.key);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_INVOICES } from "../../graphql/invoices.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -24,6 +26,8 @@ export function InvoiceExportAllButton({
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleQbxml = async () => {
|
||||
logImEXEvent("accounting_payables_export_all");
|
||||
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
@@ -117,8 +121,7 @@ export function InvoiceExportAllButton({
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
type='dashed'>
|
||||
{t("jobs.actions.exportselected")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_INVOICES } from "../../graphql/invoices.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -23,6 +25,8 @@ export function InvoiceExportButton({
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleQbxml = async () => {
|
||||
logImEXEvent("accounting_export_payable");
|
||||
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
@@ -114,8 +118,7 @@ export function InvoiceExportButton({
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
type='dashed'>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Dinero from "dinero.js";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export const CalculateInvoiceTotal = (invoice) => {
|
||||
logImEXEvent("invoice_calculate_total");
|
||||
|
||||
const {
|
||||
total,
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import JobEmployeeAssignmentsComponent from "./job-employee-assignments.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function JobEmployeeAssignmentsContainer({ job }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -11,6 +12,7 @@ export default function JobEmployeeAssignmentsContainer({ job }) {
|
||||
|
||||
const handleAdd = async (assignment) => {
|
||||
const { operation, employeeid } = assignment;
|
||||
logImEXEvent("job_assign_employee", { operation });
|
||||
|
||||
let empAssignment = determineFieldName(operation);
|
||||
|
||||
@@ -29,7 +31,8 @@ export default function JobEmployeeAssignmentsContainer({ job }) {
|
||||
}
|
||||
};
|
||||
const handleRemove = async (operation) => {
|
||||
console.log("handleRemove -> operation", operation);
|
||||
logImEXEvent("job_unassign_employee", { operation });
|
||||
|
||||
let empAssignment = determineFieldName(operation);
|
||||
const result = await updateJob({
|
||||
variables: { jobId: job.id, job: { [empAssignment]: null } },
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UPDATE_JOB } from "../../../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../../../redux/user/user.selectors";
|
||||
import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker.component";
|
||||
import ConfigFormComponents from "../../../config-form-components/config-form-components.component";
|
||||
import { logImEXEvent } from "../../../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -29,6 +30,7 @@ export function JobIntakeForm({ formItems, bodyshop }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
console.log("values", values);
|
||||
logImEXEvent("job_complete_intake");
|
||||
|
||||
const result = await intakeJob({
|
||||
variables: {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { selectBodyshop } from "../../../../redux/user/user.selectors";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -21,7 +22,10 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
export function JobIntakeTemplateList({ bodyshop, templates }) {
|
||||
const { jobId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
//TODO SHould this be using the generic one?
|
||||
const renderTemplate = async (templateKey) => {
|
||||
logImEXEvent("job_intake_template_render");
|
||||
|
||||
const html = await RenderTemplate(
|
||||
{
|
||||
name: templateKey,
|
||||
@@ -33,6 +37,8 @@ export function JobIntakeTemplateList({ bodyshop, templates }) {
|
||||
};
|
||||
|
||||
const renderAllTemplates = () => {
|
||||
logImEXEvent("job_intake_render_all_templates");
|
||||
|
||||
templates.forEach((template) => renderTemplate(template));
|
||||
};
|
||||
|
||||
|
||||
@@ -5,13 +5,16 @@ import { useTranslation } from "react-i18next";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import "./job-invoices-total.styles.scss";
|
||||
|
||||
export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (loading) return <LoadingSkeleton />;
|
||||
if (!!!jobTotals)
|
||||
return (
|
||||
<AlertComponent type='error' message={t("jobs.errors.nofinancial")} />
|
||||
);
|
||||
|
||||
const totals = JSON.parse(jobTotals);
|
||||
|
||||
let invoiceTotals = Dinero({ amount: 0 });
|
||||
|
||||
@@ -12,6 +12,7 @@ import moment from "moment";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { INSERT_SCOREBOARD_ENTRY } from "../../graphql/scoreboard.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ScoreboardAddButton({ job, ...otherBtnProps }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -21,6 +22,8 @@ export default function ScoreboardAddButton({ job, ...otherBtnProps }) {
|
||||
const [visibility, setVisibility] = useState(false);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("job_close_add_to_scoreboard");
|
||||
|
||||
setLoading(true);
|
||||
const result = await insertScoreboardEntry({
|
||||
variables: { sbInput: [{ jobid: job.id, ...values }] },
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Dinero from "dinero.js";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export function CalculateJob(job, shoprates) {
|
||||
logImEXEvent("job_calculate_total");
|
||||
|
||||
let ret = {
|
||||
parts: CalculatePartsTotals(job.joblines),
|
||||
rates: CalculateRatesTotals(job, shoprates),
|
||||
|
||||
@@ -15,6 +15,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import JobsAvailableComponent from "./jobs-available-new.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -40,6 +41,8 @@ export function JobsAvailableContainer({
|
||||
const [loadEstData, estData] = estDataLazyLoad;
|
||||
|
||||
const onModalOk = () => {
|
||||
logImEXEvent("job_import_new");
|
||||
|
||||
setModalVisible(false);
|
||||
setInsertLoading(true);
|
||||
|
||||
@@ -118,12 +121,11 @@ export function JobsAvailableContainer({
|
||||
setSelectedOwner(null);
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent type="error" message={error.message} />;
|
||||
if (error) return <AlertComponent type='error' message={error.message} />;
|
||||
return (
|
||||
<LoadingSpinner
|
||||
loading={insertLoading}
|
||||
message={t("jobs.labels.creating_new_job")}
|
||||
>
|
||||
message={t("jobs.labels.creating_new_job")}>
|
||||
<JobsAvailableComponent
|
||||
loading={loading}
|
||||
data={data}
|
||||
|
||||
@@ -18,6 +18,7 @@ import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import JobsAvailableSupplementComponent from "./jobs-available-supplement.component";
|
||||
import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util";
|
||||
import HeaderFields from "./jobs-available-supplement.headerfields";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -46,6 +47,8 @@ export function JobsAvailableSupplementContainer({
|
||||
const importOptions = importOptionsState[0];
|
||||
|
||||
const onModalOk = async () => {
|
||||
logImEXEvent("job_import_supplement");
|
||||
|
||||
setModalVisible(false);
|
||||
setInsertLoading(true);
|
||||
|
||||
@@ -137,12 +140,11 @@ export function JobsAvailableSupplementContainer({
|
||||
setSelectedJob(null);
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent type="error" message={error.message} />;
|
||||
if (error) return <AlertComponent type='error' message={error.message} />;
|
||||
return (
|
||||
<LoadingSpinner
|
||||
loading={insertLoading}
|
||||
message={t("jobs.labels.creating_new_job")}
|
||||
>
|
||||
message={t("jobs.labels.creating_new_job")}>
|
||||
<JobsAvailableSupplementComponent
|
||||
loading={loading}
|
||||
data={data}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -19,13 +20,15 @@ export function JobsCloseLabmatAllocationButton({
|
||||
allocation,
|
||||
setAllocations,
|
||||
bodyshop,
|
||||
invoiced
|
||||
invoiced,
|
||||
}) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [state, setState] = useState({ center: "", amount: 0 });
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleAllocate = () => {
|
||||
logImEXEvent("jobs_close_allocate_single");
|
||||
|
||||
const existingIndex = allocation.allocations.findIndex(
|
||||
(e) => e.center === state.center
|
||||
);
|
||||
@@ -70,8 +73,7 @@ export function JobsCloseLabmatAllocationButton({
|
||||
<Select
|
||||
style={{ width: "200px" }}
|
||||
value={state.center}
|
||||
onSelect={(val) => setState({ ...state, center: val })}
|
||||
>
|
||||
onSelect={(val) => setState({ ...state, center: val })}>
|
||||
{bodyshop.md_responsibility_centers.profits.map((r, idx) => (
|
||||
<Option key={idx} value={r.name}>
|
||||
{r.name}
|
||||
@@ -88,17 +90,25 @@ export function JobsCloseLabmatAllocationButton({
|
||||
<Button
|
||||
onClick={handleAllocate}
|
||||
disabled={
|
||||
state.amount === 0 || state.center === "" || remainingAmount === 0 || invoiced
|
||||
}
|
||||
>
|
||||
state.amount === 0 ||
|
||||
state.center === "" ||
|
||||
remainingAmount === 0 ||
|
||||
invoiced
|
||||
}>
|
||||
{t("jobs.actions.allocate")}
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
{visible ? (
|
||||
<CloseCircleFilled onClick={() => setVisible(false)} disabled={invoiced} />
|
||||
<CloseCircleFilled
|
||||
onClick={() => setVisible(false)}
|
||||
disabled={invoiced}
|
||||
/>
|
||||
) : (
|
||||
<PlusCircleFilled onClick={() => setVisible(true)} disabled={invoiced}/>
|
||||
<PlusCircleFilled
|
||||
onClick={() => setVisible(true)}
|
||||
disabled={invoiced}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -19,6 +21,8 @@ export function JobsCloseAutoAllocate({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const handleAllocate = () => {
|
||||
logImEXEvent("jobs_close_allocate_auto");
|
||||
|
||||
const { defaults } = bodyshop.md_responsibility_centers;
|
||||
|
||||
Object.keys(labmatAllocations).forEach((i) => {
|
||||
|
||||
@@ -8,6 +8,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -17,6 +19,8 @@ export function JobsCloseExportButton({ bodyshop, jobId, disabled }) {
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleQbxml = async () => {
|
||||
logImEXEvent("jobs_close_export");
|
||||
|
||||
setLoading(true);
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
@@ -107,8 +111,7 @@ export function JobsCloseExportButton({ bodyshop, jobId, disabled }) {
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
type='dashed'>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { Button, notification } from "antd";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { Button, notification } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -26,6 +27,8 @@ export function JobsCloseSaveButton({
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleSave = async () => {
|
||||
logImEXEvent("jobs_close_save");
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const result = await updateJob({
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { notification } from "antd";
|
||||
import i18n from "i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function AddToProduction(
|
||||
apolloClient,
|
||||
jobId,
|
||||
completionCallback
|
||||
) {
|
||||
logImEXEvent("job_add_to_production");
|
||||
|
||||
//get a list of all fields on the job
|
||||
apolloClient
|
||||
.mutate({
|
||||
|
||||
@@ -11,6 +11,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
|
||||
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
|
||||
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -37,9 +38,11 @@ export function JobsDetailHeaderActions({
|
||||
const client = useApolloClient();
|
||||
const history = useHistory();
|
||||
const statusmenu = (
|
||||
<Menu key="popovermenu">
|
||||
<Menu key='popovermenu'>
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
logImEXEvent("job_header_schedule");
|
||||
|
||||
setScheduleContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
@@ -47,43 +50,41 @@ export function JobsDetailHeaderActions({
|
||||
job: job,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("jobs.actions.schedule")}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="enterpayments"
|
||||
key='enterpayments'
|
||||
onClick={() => {
|
||||
logImEXEvent("job_header_enter_payment");
|
||||
|
||||
setPaymentContext({
|
||||
actions: {},
|
||||
context: { jobId: job.id },
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("menus.header.enterpayment")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="cccontract">
|
||||
<Menu.Item key='cccontract'>
|
||||
<Link
|
||||
to={{
|
||||
pathname: "/manage/courtesycars/contracts/new",
|
||||
state: { jobId: job.id },
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("menus.jobsactions.newcccontract")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="addtoproduction"
|
||||
key='addtoproduction'
|
||||
disabled={!!!job.converted || !!job.inproduction}
|
||||
onClick={() => AddToProduction(client, job.id, refetch)}
|
||||
>
|
||||
onClick={() => AddToProduction(client, job.id, refetch)}>
|
||||
{t("jobs.actions.addtoproduction")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="duplicatejob">
|
||||
<Menu.Item key='duplicatejob'>
|
||||
<Popconfirm
|
||||
title={t("jobs.labels.duplicateconfirm")}
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
okText='Yes'
|
||||
cancelText='No'
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onConfirm={() =>
|
||||
DuplicateJob(
|
||||
@@ -95,30 +96,29 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
)
|
||||
}
|
||||
getPopupContainer={(trigger) => trigger.parentNode}
|
||||
>
|
||||
getPopupContainer={(trigger) => trigger.parentNode}>
|
||||
{t("menus.jobsactions.duplicate")}
|
||||
</Popconfirm>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="postinvoices"
|
||||
key='postinvoices'
|
||||
onClick={() => {
|
||||
logImEXEvent("job_header_enter_invoice");
|
||||
|
||||
setInvoiceEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="closejob">
|
||||
<Menu.Item key='closejob'>
|
||||
<Link
|
||||
to={{
|
||||
pathname: `/manage/jobs/${job.id}/close`,
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("menus.jobsactions.closejob")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
@@ -127,11 +127,10 @@ export function JobsDetailHeaderActions({
|
||||
);
|
||||
return (
|
||||
<Dropdown
|
||||
className="imex-flex-row__margin"
|
||||
className='imex-flex-row__margin'
|
||||
overlay={statusmenu}
|
||||
trigger={["click"]}
|
||||
key="changestatus"
|
||||
>
|
||||
key='changestatus'>
|
||||
<Button>
|
||||
{t("general.labels.actions")} <DownCircleFilled />
|
||||
</Button>
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser'
|
||||
@@ -31,7 +32,7 @@ export function JobsDetailHeaderCsi({
|
||||
const client = useApolloClient();
|
||||
|
||||
const handleCreateCsi = async (e) => {
|
||||
console.log("e.target.key", e.key);
|
||||
logImEXEvent("job_create_csi");
|
||||
|
||||
const questionSetResult = await client.query({
|
||||
query: GET_CURRENT_QUESTIONSET_ID,
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
QUERY_ALL_JOB_FIELDS,
|
||||
INSERT_NEW_JOB,
|
||||
} from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function DuplicateJob(
|
||||
apolloClient,
|
||||
@@ -9,6 +10,8 @@ export default function DuplicateJob(
|
||||
config,
|
||||
completionCallback
|
||||
) {
|
||||
logImEXEvent("job_duplicate");
|
||||
|
||||
const { defaultOpenStatus } = config;
|
||||
//get a list of all fields on the job
|
||||
apolloClient
|
||||
|
||||
@@ -2,11 +2,14 @@ import { Button } from "antd";
|
||||
import axios from "axios";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function JobsDocumentsDownloadButton({ galleryImages }) {
|
||||
const { t } = useTranslation();
|
||||
const imagesToDownload = galleryImages.filter((image) => image.isSelected);
|
||||
const handleDelete = () => {
|
||||
const handleDownload = () => {
|
||||
logImEXEvent("jobs_documents_download");
|
||||
|
||||
axios
|
||||
.post("/media/download", {
|
||||
ids: imagesToDownload.map((_) => _.key),
|
||||
@@ -17,7 +20,7 @@ export default function JobsDocumentsDownloadButton({ galleryImages }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Button disabled={imagesToDownload.length < 1} onClick={handleDelete}>
|
||||
<Button disabled={imagesToDownload.length < 1} onClick={handleDownload}>
|
||||
{t("documents.actions.download")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import axios from "axios";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { DELETE_DOCUMENT } from "../../graphql/documents.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function JobsDocumentsDeleteButton({
|
||||
galleryImages,
|
||||
@@ -13,6 +14,8 @@ export default function JobsDocumentsDeleteButton({
|
||||
const [deleteDocument] = useMutation(DELETE_DOCUMENT);
|
||||
const imagesToDelete = galleryImages.filter((image) => image.isSelected);
|
||||
const handleDelete = () => {
|
||||
logImEXEvent("job_documents_delete", { count: imagesToDelete.length });
|
||||
|
||||
imagesToDelete.forEach((image) => {
|
||||
let timestamp = Math.floor(Date.now() / 1000);
|
||||
let public_id = image.key;
|
||||
|
||||
@@ -9,12 +9,13 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Moment from "react-moment";
|
||||
import { connect } from "react-redux";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
setNoteUpsertContext: context =>
|
||||
dispatch(setModalContext({ context: context, modal: "noteUpsert" }))
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setNoteUpsertContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "noteUpsert" })),
|
||||
});
|
||||
|
||||
export function JobNotesComponent({
|
||||
@@ -23,7 +24,7 @@ export function JobNotesComponent({
|
||||
refetch,
|
||||
deleteNote,
|
||||
jobId,
|
||||
setNoteUpsertContext
|
||||
setNoteUpsertContext,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -40,13 +41,13 @@ export function JobNotesComponent({
|
||||
) : null}
|
||||
{record.private ? <EyeInvisibleFilled style={{ margin: 4 }} /> : null}
|
||||
</span>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("notes.fields.text"),
|
||||
dataIndex: "text",
|
||||
key: "text",
|
||||
ellipsis: true
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
@@ -58,15 +59,15 @@ export function JobNotesComponent({
|
||||
sorter: (a, b) => new Date(a.updated_at) - new Date(b.updated_at),
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<Moment format="MM/DD/YYYY @ HH:mm">{record.updated_at}</Moment>
|
||||
<Moment format='MM/DD/YYYY @ HH:mm'>{record.updated_at}</Moment>
|
||||
</span>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("notes.fields.createdby"),
|
||||
dataIndex: "created_by",
|
||||
key: "created_by",
|
||||
width: 200
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: t("notes.actions.actions"),
|
||||
@@ -77,18 +78,19 @@ export function JobNotesComponent({
|
||||
<span>
|
||||
<Button
|
||||
onClick={() => {
|
||||
logImEXEvent("job_note_delete");
|
||||
|
||||
deleteNote({
|
||||
variables: {
|
||||
noteId: record.id
|
||||
}
|
||||
}).then(r => {
|
||||
noteId: record.id,
|
||||
},
|
||||
}).then((r) => {
|
||||
refetch();
|
||||
notification["success"]({
|
||||
message: t("notes.successes.deleted")
|
||||
message: t("notes.successes.deleted"),
|
||||
});
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<DeleteFilled />
|
||||
</Button>
|
||||
<Button
|
||||
@@ -97,16 +99,15 @@ export function JobNotesComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
jobId: jobId,
|
||||
existingNote: record
|
||||
}
|
||||
existingNote: record,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<EditFilled />
|
||||
</Button>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -117,18 +118,17 @@ export function JobNotesComponent({
|
||||
setNoteUpsertContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
jobId: jobId
|
||||
}
|
||||
jobId: jobId,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{t("notes.actions.new")}
|
||||
</Button>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{ position: "bottom" }}
|
||||
columns={columns.map(item => ({ ...item }))}
|
||||
rowKey="id"
|
||||
columns={columns.map((item) => ({ ...item }))}
|
||||
rowKey='id'
|
||||
dataSource={data}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,19 +9,20 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||
import { selectNoteUpsert } from "../../redux/modals/modals.selectors";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import NoteUpsertModalComponent from "./note-upsert-modal.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
noteUpsertModal: selectNoteUpsert
|
||||
noteUpsertModal: selectNoteUpsert,
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert"))
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert")),
|
||||
});
|
||||
|
||||
export function NoteUpsertModalContainer({
|
||||
currentUser,
|
||||
noteUpsertModal,
|
||||
toggleModalVisible
|
||||
toggleModalVisible,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [insertNote] = useMutation(INSERT_NEW_NOTE);
|
||||
@@ -40,32 +41,36 @@ export function NoteUpsertModalContainer({
|
||||
}
|
||||
}, [existingNote, form]);
|
||||
|
||||
const handleFinish = values => {
|
||||
const handleFinish = (values) => {
|
||||
if (existingNote) {
|
||||
logImEXEvent("job_note_update");
|
||||
|
||||
updateNote({
|
||||
variables: {
|
||||
noteId: existingNote.id,
|
||||
note: values
|
||||
}
|
||||
}).then(r => {
|
||||
note: values,
|
||||
},
|
||||
}).then((r) => {
|
||||
notification["success"]({
|
||||
message: t("notes.successes.updated")
|
||||
message: t("notes.successes.updated"),
|
||||
});
|
||||
});
|
||||
if (refetch) refetch();
|
||||
toggleModalVisible();
|
||||
} else {
|
||||
logImEXEvent("job_note_insert");
|
||||
|
||||
insertNote({
|
||||
variables: {
|
||||
noteInput: [
|
||||
{ ...values, jobid: jobId, created_by: currentUser.email }
|
||||
]
|
||||
}
|
||||
}).then(r => {
|
||||
{ ...values, jobid: jobId, created_by: currentUser.email },
|
||||
],
|
||||
},
|
||||
}).then((r) => {
|
||||
if (refetch) refetch();
|
||||
toggleModalVisible();
|
||||
notification["success"]({
|
||||
message: t("notes.successes.create")
|
||||
message: t("notes.successes.create"),
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -82,8 +87,7 @@ export function NoteUpsertModalContainer({
|
||||
onCancel={() => {
|
||||
toggleModalVisible();
|
||||
}}
|
||||
destroyOnClose
|
||||
>
|
||||
destroyOnClose>
|
||||
<Form form={form} onFinish={handleFinish} initialValues={existingNote}>
|
||||
<NoteUpsertModalComponent />
|
||||
</Form>
|
||||
|
||||
@@ -3,15 +3,18 @@ import { Button, notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { UPDATE_JOBS } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function OwnerDetailUpdateJobsComponent({
|
||||
owner,
|
||||
selectedJobs,
|
||||
disabled
|
||||
disabled,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [updateJobs] = useMutation(UPDATE_JOBS);
|
||||
const handlecClick = e => {
|
||||
const handlecClick = (e) => {
|
||||
logImEXEvent("owner_update_jobs", { count: selectedJobs.length });
|
||||
|
||||
updateJobs({
|
||||
variables: {
|
||||
jobIds: selectedJobs,
|
||||
@@ -28,16 +31,16 @@ export default function OwnerDetailUpdateJobsComponent({
|
||||
ownr_ph2: owner["ownr_ph2"],
|
||||
ownr_st: owner["ownr_st"],
|
||||
ownr_title: owner["ownr_title"],
|
||||
ownr_zip: owner["ownr_zip"]
|
||||
}
|
||||
}
|
||||
ownr_zip: owner["ownr_zip"],
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
notification["success"]({ message: t("jobs.successes.updated") });
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.updating", { error: JSON.stringify(error) })
|
||||
message: t("jobs.errors.updating", { error: JSON.stringify(error) }),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MUTATION_BACKORDER_PART_LINE } from "../../graphql/parts-orders.queries
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -26,6 +27,7 @@ export function PartsOrderLineBackorderButton({
|
||||
|
||||
const handleOnClick = async () => {
|
||||
setLoading(true);
|
||||
logImEXEvent("job_parts_backorder");
|
||||
|
||||
const result = await backorderLine({
|
||||
variables: {
|
||||
|
||||
@@ -23,6 +23,7 @@ import RenderTemplate, {
|
||||
} from "../../utils/RenderTemplate";
|
||||
import moment from "moment";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -68,6 +69,8 @@ export function PartsOrderModalContainer({
|
||||
const [insertInvoice] = useMutation(INSERT_NEW_INVOICE);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("parts_order_insert");
|
||||
|
||||
const insertResult = await insertPartOrder({
|
||||
variables: {
|
||||
po: [
|
||||
@@ -109,11 +112,13 @@ export function PartsOrderModalContainer({
|
||||
|
||||
if (values.vendorid === bodyshop.inhousevendorid) {
|
||||
console.log("Inhouse Invoice needs to be psoted.");
|
||||
logImEXEvent("parts_order_inhouse_invoice");
|
||||
|
||||
let invoiceToPost = {
|
||||
vendorid: bodyshop.inhousevendorid,
|
||||
jobid: jobId,
|
||||
total: 0,
|
||||
invoice_number: `${jobId}`,
|
||||
invoice_number: `${jobId}`,
|
||||
federal_tax_rate: bodyshop.invoice_tax_rates.federal_tax_rate || 0,
|
||||
state_tax_rate: bodyshop.invoice_tax_rates.state_tax_rate || 0,
|
||||
local_tax_rate: bodyshop.invoice_tax_rates.local_tax_rate || 0,
|
||||
|
||||
@@ -8,6 +8,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_PAYMENTS } from "../../graphql/payments.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -23,6 +25,8 @@ export function PaymentExportButton({
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleQbxml = async () => {
|
||||
logImEXEvent("accounting_payment_export");
|
||||
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
@@ -114,8 +118,7 @@ export function PaymentExportButton({
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
type='dashed'>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -19,6 +19,7 @@ import RenderTemplate, {
|
||||
displayTemplateInWindow,
|
||||
} from "../../utils/RenderTemplate";
|
||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
paymentModal: selectPayment,
|
||||
@@ -69,6 +70,8 @@ function InvoiceEnterModalContainer({
|
||||
try {
|
||||
let stripePayment;
|
||||
if (useStripe && bodyshop.stripe_acct_id) {
|
||||
logImEXEvent("payment_stripe_attempt");
|
||||
|
||||
const secretKey = await axios.post("/stripe/payment", {
|
||||
amount: Math.round(values.amount * 100),
|
||||
stripe_acct_id: bodyshop.stripe_acct_id,
|
||||
@@ -94,6 +97,7 @@ function InvoiceEnterModalContainer({
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
logImEXEvent("payment_insert");
|
||||
|
||||
const newPayment = await insertPayment({
|
||||
variables: {
|
||||
@@ -168,15 +172,13 @@ function InvoiceEnterModalContainer({
|
||||
okButtonProps={{
|
||||
loading: loading,
|
||||
}}
|
||||
destroyOnClose
|
||||
>
|
||||
destroyOnClose>
|
||||
<Form
|
||||
onFinish={handleFinish}
|
||||
autoComplete={"off"}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{ jobid: context.jobId }}
|
||||
>
|
||||
layout='vertical'
|
||||
initialValues={{ jobid: context.jobId }}>
|
||||
<PaymentForm form={form} stripeStateArr={stripeStateArr} />
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -44,7 +44,7 @@ export function PrintCenterItemComponent({
|
||||
onClick={() => {
|
||||
setEmailOptions({
|
||||
messageOptions: {
|
||||
Subject: "TODO FIX ME",
|
||||
Subject: "//TODO FIX ME",
|
||||
},
|
||||
template: {
|
||||
name: item.key,
|
||||
|
||||
@@ -11,6 +11,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
||||
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -39,6 +40,8 @@ export function ProductionBoardKanbanComponent({ data, bodyshop }) {
|
||||
const client = useApolloClient();
|
||||
|
||||
const handleDragEnd = async (card, source, destination) => {
|
||||
logImEXEvent("kanban_drag_end");
|
||||
|
||||
setIsMoving(true);
|
||||
setBoardLanes(moveCard(boardLanes, source, destination));
|
||||
const sameColumnTransfer = source.fromColumnId === destination.toColumnId;
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionListColumnAlert({ record }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -11,6 +12,8 @@ export default function ProductionListColumnAlert({ record }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleAlertToggle = () => {
|
||||
logImEXEvent("production_toggle_alert");
|
||||
|
||||
updateAlert({
|
||||
variables: {
|
||||
jobId: record.id,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Dropdown, Menu } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionListColumnBodyPriority({ record }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -10,6 +11,8 @@ export default function ProductionListColumnBodyPriority({ record }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleSetBodyPriority = (e) => {
|
||||
logImEXEvent("production_set_body_priority");
|
||||
|
||||
const { key } = e;
|
||||
updateAlert({
|
||||
variables: {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Dropdown, Menu } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionListColumnPaintPriority({ record }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -10,6 +11,8 @@ export default function ProductionListColumnPaintPriority({ record }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleSetPaintPriority = (e) => {
|
||||
logImEXEvent("production_set_paint_priority");
|
||||
|
||||
const { key } = e;
|
||||
updateAlert({
|
||||
variables: {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Button, Input, Popover } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionListColumnProductionNote({ record }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -16,6 +17,8 @@ export default function ProductionListColumnProductionNote({ record }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleSaveNote = (e) => {
|
||||
logImEXEvent("production_add_note");
|
||||
|
||||
setVisible(false);
|
||||
updateAlert({
|
||||
variables: {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -14,6 +15,8 @@ export function ProductionListColumnStatus({ record, bodyshop }) {
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleSetStatus = (e) => {
|
||||
logImEXEvent("production_change_status");
|
||||
|
||||
const { key } = e;
|
||||
updateJob({
|
||||
variables: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { Button } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_SHOP } from "../../graphql/bodyshop.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -24,6 +25,8 @@ export function ProductionListSaveConfigButton({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
logImEXEvent("production_save_config");
|
||||
|
||||
updateShop({
|
||||
variables: {
|
||||
id: bodyshop.id,
|
||||
|
||||
@@ -3,11 +3,14 @@ import { useMutation } from "@apollo/react-hooks";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { Button, notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionRemoveButton({ jobId }) {
|
||||
const [removeJobFromProduction] = useMutation(UPDATE_JOB);
|
||||
const { t } = useTranslation();
|
||||
const handleRemoveFromProd = () => {
|
||||
logImEXEvent("production_remove_job");
|
||||
|
||||
removeJobFromProduction({
|
||||
variables: { jobId: jobId, job: { inproduction: false } },
|
||||
}).catch((error) => {
|
||||
|
||||
@@ -5,12 +5,13 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { updateUserDetails } from "../../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
updateUserDetails: userDetails => dispatch(updateUserDetails(userDetails))
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
updateUserDetails: (userDetails) => dispatch(updateUserDetails(userDetails)),
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
@@ -18,10 +19,12 @@ export default connect(
|
||||
)(function ProfileMyComponent({ currentUser, updateUserDetails }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleFinish = values => {
|
||||
const handleFinish = (values) => {
|
||||
logImEXEvent("profile_update");
|
||||
|
||||
updateUserDetails({
|
||||
displayName: values.displayName,
|
||||
photoURL: values.photoURL
|
||||
photoURL: values.photoURL,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -30,25 +33,23 @@ export default connect(
|
||||
<Form
|
||||
onFinish={handleFinish}
|
||||
autoComplete={"no"}
|
||||
initialValues={currentUser}
|
||||
>
|
||||
initialValues={currentUser}>
|
||||
<Form.Item
|
||||
label={t("user.fields.displayname")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required")
|
||||
}
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
name="displayName"
|
||||
>
|
||||
name='displayName'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("user.fields.photourl")} name="photoURL">
|
||||
<Form.Item label={t("user.fields.photourl")} name='photoURL'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Button type="primary" key="submit" htmlType="submit">
|
||||
<Button type='primary' key='submit' htmlType='submit'>
|
||||
{t("user.actions.updateprofile")}
|
||||
</Button>
|
||||
</Form>
|
||||
|
||||
@@ -2,28 +2,31 @@ import React from "react";
|
||||
import { useQuery, useMutation } from "@apollo/react-hooks";
|
||||
import {
|
||||
QUERY_ALL_ASSOCIATIONS,
|
||||
UPDATE_ASSOCIATION
|
||||
UPDATE_ASSOCIATION,
|
||||
} from "../../graphql/associations.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ProfileShopsComponent from "./profile-shops.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProfileShopsContainer() {
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ASSOCIATIONS);
|
||||
const [updateAssocation] = useMutation(UPDATE_ASSOCIATION);
|
||||
|
||||
const updateActiveShop = activeShopId => {
|
||||
data.associations.forEach(record => {
|
||||
const updateActiveShop = (activeShopId) => {
|
||||
logImEXEvent("profile_change_active_shop");
|
||||
|
||||
data.associations.forEach((record) => {
|
||||
updateAssocation({
|
||||
variables: {
|
||||
assocId: record.id,
|
||||
assocActive: record.id === activeShopId ? true : false
|
||||
}
|
||||
assocActive: record.id === activeShopId ? true : false,
|
||||
},
|
||||
});
|
||||
});
|
||||
refetch();
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent type="error" message={error.message} />;
|
||||
if (error) return <AlertComponent type='error' message={error.message} />;
|
||||
return (
|
||||
<ProfileShopsComponent
|
||||
loading={loading}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { INSERT_APPOINTMENT } from "../../graphql/appointments.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -22,10 +23,10 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
|
||||
|
||||
const handleMenu = async (e) => {
|
||||
e.domEvent.stopPropagation();
|
||||
console.log("date", date);
|
||||
|
||||
|
||||
if (e.key === "block") {
|
||||
console.log("Block.");
|
||||
|
||||
|
||||
const blockAppt = {
|
||||
title: t("appointments.labels.blocked"),
|
||||
@@ -35,7 +36,8 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
|
||||
start: moment(date).startOf("day"),
|
||||
end: moment(date).endOf("day"),
|
||||
};
|
||||
console.log("handleMenu -> blockAppt", blockAppt);
|
||||
logImEXEvent("dashboard_change_layout");
|
||||
|
||||
|
||||
const result = await insertBlock({
|
||||
variables: { app: [blockAppt] },
|
||||
|
||||
@@ -5,13 +5,15 @@ import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import ScheduleEventComponent from "./schedule-event.component";
|
||||
import { notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ScheduleEventContainer({ event, refetch }) {
|
||||
const { t } = useTranslation();
|
||||
const [cancelAppointment] = useMutation(CANCEL_APPOINTMENT_BY_ID);
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
const handleCancel = async (id) => {
|
||||
logImEXEvent("schedule_cancel_appt");
|
||||
|
||||
const cancelAppt = await cancelAppointment({
|
||||
variables: { appid: event.id },
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { selectSchedule } from "../../redux/modals/modals.selectors";
|
||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -64,6 +65,8 @@ export function ScheduleJobModalContainer({
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
logImEXEvent("schedule_new_appointment");
|
||||
|
||||
setLoading(true);
|
||||
if (!!previousEvent) {
|
||||
const cancelAppt = await cancelAppointment({
|
||||
|
||||
@@ -4,12 +4,15 @@ import { Button, notification } from "antd";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { DELETE_SCOREBOARD_ENTRY } from "../../graphql/scoreboard.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ScoreboardRemoveButton({ scoreboardId }) {
|
||||
const { t } = useTranslation();
|
||||
const [deleteScoreboardEntry] = useMutation(DELETE_SCOREBOARD_ENTRY);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleDelete = async (e) => {
|
||||
logImEXEvent("scoreboard_remove_job");
|
||||
|
||||
e.stopPropagation();
|
||||
setLoading(true);
|
||||
const result = await deleteScoreboardEntry({
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ShopEmployeeComponent from "./shop-employees.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -30,6 +31,8 @@ function ShopEmployeesContainer({ bodyshop }) {
|
||||
const [insertEmployees] = useMutation(INSERT_EMPLOYEES);
|
||||
const [deleteEmployee] = useMutation(DELETE_EMPLOYEE);
|
||||
const handleDelete = (id) => {
|
||||
logImEXEvent("shop_employee_delete");
|
||||
|
||||
deleteEmployee({ variables: { id: id } })
|
||||
.then((r) => {
|
||||
notification["success"]({
|
||||
@@ -52,6 +55,8 @@ function ShopEmployeesContainer({ bodyshop }) {
|
||||
console.log("values", values);
|
||||
if (employeeState[0].id) {
|
||||
//Update a record.
|
||||
logImEXEvent("shop_employee_update");
|
||||
|
||||
updateEmployee({
|
||||
variables: { id: employeeState[0].id, employee: values },
|
||||
})
|
||||
@@ -72,6 +77,8 @@ function ShopEmployeesContainer({ bodyshop }) {
|
||||
});
|
||||
} else {
|
||||
//New record, insert it.
|
||||
logImEXEvent("shop_employee_insert");
|
||||
|
||||
insertEmployees({
|
||||
variables: { employees: [{ ...values, shopid: bodyshop.id }] },
|
||||
}).then((r) => {
|
||||
|
||||
@@ -6,6 +6,8 @@ import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ShopInfoContainer() {
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslation();
|
||||
@@ -16,6 +18,7 @@ export default function ShopInfoContainer() {
|
||||
|
||||
const handleFinish = values => {
|
||||
console.log("values", values);
|
||||
logImEXEvent("shop_update");
|
||||
|
||||
updateBodyshop({
|
||||
variables: { id: data.bodyshops[0].id, shop: values }
|
||||
|
||||
@@ -10,6 +10,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { INSERT_TEMPLATE } from "../../graphql/templates.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -34,6 +35,8 @@ export function ShopTemplateAddComponent({
|
||||
);
|
||||
|
||||
const handleAdd = async (item) => {
|
||||
logImEXEvent("shop_template_add");
|
||||
|
||||
const result = await insertTemplate({
|
||||
variables: {
|
||||
template: {
|
||||
|
||||
@@ -5,6 +5,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import { DELETE_TEMPLATE } from "../../graphql/templates.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ShopTemplateDeleteComponent({ templateId, refetch }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -13,6 +14,8 @@ export default function ShopTemplateDeleteComponent({ templateId, refetch }) {
|
||||
const [deleteTemplate] = useMutation(DELETE_TEMPLATE);
|
||||
|
||||
const handleDelete = async () => {
|
||||
logImEXEvent("shop_template_delete");
|
||||
|
||||
const result = await deleteTemplate({
|
||||
variables: {
|
||||
templateId: templateId,
|
||||
|
||||
@@ -3,12 +3,15 @@ import { Button, notification } from "antd";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_TEMPLATE } from "../../graphql/templates.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ShopTemplateSaveButton({ templateId, html, gql }) {
|
||||
const { t } = useTranslation();
|
||||
const [updateTemplate] = useMutation(UPDATE_TEMPLATE);
|
||||
|
||||
const handleSave = async () => {
|
||||
logImEXEvent("shop_template_update");
|
||||
|
||||
const result = await updateTemplate({
|
||||
variables: {
|
||||
templateId: templateId,
|
||||
|
||||
@@ -17,6 +17,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
technician: selectTechnician,
|
||||
@@ -37,6 +39,8 @@ export function TechClockOffButton({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("tech_clock_out_job");
|
||||
|
||||
setLoading(true);
|
||||
const result = await updateTimeticket({
|
||||
variables: {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { DeleteFilled } from "@ant-design/icons";
|
||||
import { DELETE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function TechJobClockoutDelete({
|
||||
timeTicketId,
|
||||
@@ -12,6 +13,8 @@ export default function TechJobClockoutDelete({
|
||||
const [deleteTimeTicket] = useMutation(DELETE_TIME_TICKET);
|
||||
const { t } = useTranslation();
|
||||
const handleDelete = async () => {
|
||||
logImEXEvent("tech_clock_delete");
|
||||
|
||||
const result = await deleteTimeTicket({
|
||||
variables: { id: timeTicketId },
|
||||
refetchQueries: ["QUERY_ACTIVE_TIME_TICKETS"],
|
||||
|
||||
@@ -3,15 +3,18 @@ import { Button, notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { UPDATE_JOBS } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function VehicleDetailUpdateJobsComponent({
|
||||
vehicle,
|
||||
selectedJobs,
|
||||
disabled
|
||||
disabled,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [updateJobs] = useMutation(UPDATE_JOBS);
|
||||
const handlecClick = e => {
|
||||
const handlecClick = (e) => {
|
||||
logImEXEvent("vehicle_update_jobs");
|
||||
|
||||
updateJobs({
|
||||
variables: {
|
||||
jobIds: selectedJobs,
|
||||
@@ -22,16 +25,16 @@ export default function VehicleDetailUpdateJobsComponent({
|
||||
v_model_yr: vehicle["v_model_yr"],
|
||||
v_model_desc: vehicle["v_model_desc"],
|
||||
v_make_desc: vehicle["v_make_desc"],
|
||||
v_color: vehicle["v_color"]
|
||||
}
|
||||
}
|
||||
v_color: vehicle["v_color"],
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
notification["success"]({ message: t("jobs.successes.updated") });
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.updating", { error: JSON.stringify(error) })
|
||||
message: t("jobs.errors.updating", { error: JSON.stringify(error) }),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ try {
|
||||
|
||||
export { messaging };
|
||||
|
||||
export const logImEXEvent = async (eventName, additionalParams) => {
|
||||
export const logImEXEvent = (eventName, additionalParams) => {
|
||||
const state = store.getState();
|
||||
const eventParams = {
|
||||
shop:
|
||||
|
||||
@@ -2,23 +2,35 @@ import axios from "axios";
|
||||
import phone from "phone";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { client } from "../../App/App.container";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import {
|
||||
CONVERSATION_ID_BY_PHONE,
|
||||
CREATE_CONVERSATION,
|
||||
} from "../../graphql/conversations.queries";
|
||||
import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||
import { selectBodyshop } from "../user/user.selectors";
|
||||
import {
|
||||
sendMessageFailure,
|
||||
sendMessageSuccess,
|
||||
setSelectedConversation,
|
||||
} from "./messaging.actions";
|
||||
import MessagingActionTypes from "./messaging.types";
|
||||
import { selectBodyshop } from "../user/user.selectors";
|
||||
|
||||
export function* onToggleChatVisible() {
|
||||
yield takeLatest(MessagingActionTypes.TOGGLE_CHAT_VISIBLE, toggleChatLogging);
|
||||
}
|
||||
export function* toggleChatLogging() {
|
||||
try {
|
||||
yield logImEXEvent("messaging_toggle_popup");
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
}
|
||||
}
|
||||
export function* onOpenChatByPhone() {
|
||||
yield takeLatest(MessagingActionTypes.OPEN_CHAT_BY_PHONE, openChatByPhone);
|
||||
}
|
||||
export function* openChatByPhone({ payload }) {
|
||||
logImEXEvent("messaging_open_by_phone");
|
||||
const { phone_num, jobid } = payload;
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
try {
|
||||
@@ -69,6 +81,8 @@ export function* onSendMessage() {
|
||||
}
|
||||
export function* sendMessage({ payload }) {
|
||||
try {
|
||||
yield logImEXEvent("messaging_send_message");
|
||||
|
||||
const response = yield call(axios.post, "/sms/send", payload);
|
||||
if (response.status === 200) {
|
||||
yield put(sendMessageSuccess(payload));
|
||||
@@ -82,5 +96,9 @@ export function* sendMessage({ payload }) {
|
||||
}
|
||||
|
||||
export function* messagingSagas() {
|
||||
yield all([call(onSendMessage), call(onOpenChatByPhone)]);
|
||||
yield all([
|
||||
call(onSendMessage),
|
||||
call(onOpenChatByPhone),
|
||||
call(onToggleChatVisible),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ModalsActionTypes from "./modals.types";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const baseModal = {
|
||||
visible: false,
|
||||
@@ -24,6 +25,7 @@ const INITIAL_STATE = {
|
||||
const modalsReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case ModalsActionTypes.TOGGLE_MODAL_VISIBLE:
|
||||
logImEXEvent("redux_toggle_modal_visible", { modal: action.payload });
|
||||
return {
|
||||
...state,
|
||||
[action.payload]: {
|
||||
@@ -32,6 +34,8 @@ const modalsReducer = (state = INITIAL_STATE, action) => {
|
||||
},
|
||||
};
|
||||
case ModalsActionTypes.SET_MODAL_CONTEXT:
|
||||
logImEXEvent("redux_set_modal_context", { modal: action.payload.modal });
|
||||
|
||||
return {
|
||||
...state,
|
||||
[action.payload.modal]: {
|
||||
|
||||
@@ -3,30 +3,25 @@ import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { selectBodyshop } from "../user/user.selectors";
|
||||
import { techLoginFailure, techLoginSuccess } from "./tech.actions";
|
||||
import TechActionTypes from "./tech.types";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export function* onSignInStart() {
|
||||
yield takeLatest(TechActionTypes.TECH_LOGIN_START, signInStart);
|
||||
}
|
||||
export function* signInStart({ payload: { employeeid, pin } }) {
|
||||
try {
|
||||
logImEXEvent("redux_tech_sign_in");
|
||||
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
const response = yield call(axios.post, "/tech/login", {
|
||||
shopid: bodyshop.id,
|
||||
employeeid: employeeid,
|
||||
pin: pin,
|
||||
});
|
||||
console.log("response", response);
|
||||
|
||||
const { valid, technician, error } = response.data;
|
||||
|
||||
console.log(
|
||||
"function*signInStart -> valid, technician, erro",
|
||||
valid,
|
||||
technician,
|
||||
error
|
||||
);
|
||||
|
||||
if (valid) {
|
||||
console.log("Valid in else");
|
||||
yield put(techLoginSuccess(technician));
|
||||
} else {
|
||||
yield put(techLoginFailure(error));
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { all, call, put, takeLatest, delay, select } from "redux-saga/effects";
|
||||
import LogRocket from "logrocket";
|
||||
import { firestore } from "../../firebase/firebase.utils";
|
||||
import Fingerprint2 from "fingerprintjs2";
|
||||
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
|
||||
import {
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
updateCurrentUser,
|
||||
} from "../../firebase/firebase.utils";
|
||||
import {
|
||||
checkInstanceId,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
setInstanceId,
|
||||
checkInstanceId,
|
||||
setLocalFingerprint,
|
||||
setInstanceConflict,
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
@@ -27,6 +27,8 @@ export function* onEmailSignInStart() {
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", { user: email });
|
||||
|
||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||
|
||||
yield put(
|
||||
@@ -40,6 +42,7 @@ export function* signInWithEmail({ payload: { email, password } }) {
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", { user: email, error });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +51,8 @@ export function* onCheckUserSession() {
|
||||
}
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
@@ -73,6 +78,8 @@ export function* onSignOutStart() {
|
||||
}
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
yield auth.signOut();
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
@@ -135,6 +142,7 @@ export function* checkInstanceIdSaga({ payload: uid }) {
|
||||
yield put(checkInstanceId(uid));
|
||||
} else {
|
||||
console.log("ERROR: Fingerprints do not match. Conflict detected.");
|
||||
logImEXEvent("instance_confict");
|
||||
yield put(setInstanceConflict());
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -150,6 +158,7 @@ export function* onSignInSuccess() {
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
LogRocket.identify(payload.email);
|
||||
yield put(setInstanceId(payload.uid));
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
}
|
||||
|
||||
export function* userSagas() {
|
||||
|
||||
Reference in New Issue
Block a user