CLEANUP Refactored note upsert to use redux modals.

This commit is contained in:
Patrick Fic
2020-04-02 12:05:32 -07:00
parent 922463d400
commit 828ca721db
8 changed files with 156 additions and 143 deletions

View File

@@ -30,8 +30,6 @@ export function InvoiceEnterModalContainer({
const [form] = Form.useForm(); const [form] = Form.useForm();
const [updateContract] = useMutation(RETURN_CONTRACT); const [updateContract] = useMutation(RETURN_CONTRACT);
const handleFinish = values => { const handleFinish = values => {
console.log("Finish", values);
updateContract({ updateContract({
variables: { variables: {
contractId: context.contractId, contractId: context.contractId,

View File

@@ -16,7 +16,6 @@ import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
import ScheduleJobModalContainer from "../schedule-job-modal/schedule-job-modal.container"; import ScheduleJobModalContainer from "../schedule-job-modal/schedule-job-modal.container";
//import JobDetailCardsHeaderComponent from "./job-detail-cards.header.component";
import JobDetailCardsCustomerComponent from "./job-detail-cards.customer.component"; import JobDetailCardsCustomerComponent from "./job-detail-cards.customer.component";
import JobDetailCardsDamageComponent from "./job-detail-cards.damage.component"; import JobDetailCardsDamageComponent from "./job-detail-cards.damage.component";
import JobDetailCardsDatesComponent from "./job-detail-cards.dates.component"; import JobDetailCardsDatesComponent from "./job-detail-cards.dates.component";
@@ -29,16 +28,21 @@ import JobDetailCardsTotalsComponent from "./job-detail-cards.totals.component";
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
setInvoiceEnterContext: context => setInvoiceEnterContext: context =>
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })) dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
setNoteUpsertContext: context =>
dispatch(setModalContext({ context: context, modal: "noteUpsert" }))
}); });
function JobDetailCards({ selectedJob, setInvoiceEnterContext }) { export function JobDetailCards({
selectedJob,
setInvoiceEnterContext,
setNoteUpsertContext
}) {
const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, { const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, {
fetchPolicy: "network-only", fetchPolicy: "network-only",
variables: { id: selectedJob }, variables: { id: selectedJob },
skip: !selectedJob skip: !selectedJob
}); });
const [noteModalVisible, setNoteModalVisible] = useState(false);
const scheduleModalState = useState(false); const scheduleModalState = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
@@ -50,12 +54,7 @@ function JobDetailCards({ selectedJob, setInvoiceEnterContext }) {
return ( return (
<div className="job-cards-container"> <div className="job-cards-container">
<NoteUpsertModal <NoteUpsertModal />
jobId={data.jobs_by_pk.id}
visible={noteModalVisible}
changeVisibility={setNoteModalVisible}
refetch={refetch}
/>
<ScheduleJobModalContainer <ScheduleJobModalContainer
scheduleModalState={scheduleModalState} scheduleModalState={scheduleModalState}
jobId={data.jobs_by_pk.id} jobId={data.jobs_by_pk.id}
@@ -110,7 +109,12 @@ function JobDetailCards({ selectedJob, setInvoiceEnterContext }) {
key="notes" key="notes"
actiontype="addNote" actiontype="addNote"
onClick={() => { onClick={() => {
setNoteModalVisible(!noteModalVisible); setNoteUpsertContext({
actions: { refetch: refetch },
context: {
jobId: data.jobs_by_pk.id
}
});
}} }}
> >
<EditFilled /> <EditFilled />
@@ -120,7 +124,7 @@ function JobDetailCards({ selectedJob, setInvoiceEnterContext }) {
key="postinvoices" key="postinvoices"
onClick={() => { onClick={() => {
setInvoiceEnterContext({ setInvoiceEnterContext({
actions: { refetch: null }, actions: { refetch: refetch },
context: { context: {
job: data.jobs_by_pk job: data.jobs_by_pk
} }

View File

@@ -1,25 +1,32 @@
import React, { useState } from "react";
import { Table, Button, notification } from "antd";
import { import {
WarningFilled,
EyeInvisibleFilled,
DeleteFilled, DeleteFilled,
EditFilled EditFilled,
EyeInvisibleFilled,
WarningFilled
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Button, notification, Table } from "antd";
import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Moment from "react-moment"; import Moment from "react-moment";
import { connect } from "react-redux";
import { setModalContext } from "../../redux/modals/modals.actions";
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
export default function JobNotesComponent({ const mapDispatchToProps = dispatch => ({
setNoteUpsertContext: context =>
dispatch(setModalContext({ context: context, modal: "noteUpsert" }))
});
export function JobNotesComponent({
loading, loading,
data, data,
refetch, refetch,
deleteNote, deleteNote,
jobId jobId,
setNoteUpsertContext
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [noteModalVisible, setNoteModalVisible] = useState(false);
const [existingNote, setExistingNote] = useState(null);
const columns = [ const columns = [
{ {
title: "", title: "",
@@ -28,7 +35,6 @@ export default function JobNotesComponent({
width: 80, width: 80,
render: (text, record) => ( render: (text, record) => (
<span> <span>
{" "}
{record.critical ? ( {record.critical ? (
<WarningFilled style={{ margin: 4, color: "red" }} /> <WarningFilled style={{ margin: 4, color: "red" }} />
) : null} ) : null}
@@ -87,8 +93,13 @@ export default function JobNotesComponent({
</Button> </Button>
<Button <Button
onClick={() => { onClick={() => {
setExistingNote(record); setNoteUpsertContext({
setNoteModalVisible(true); actions: { refetch: refetch },
context: {
jobId: jobId,
existingNote: record
}
});
}} }}
> >
<EditFilled /> <EditFilled />
@@ -100,17 +111,15 @@ export default function JobNotesComponent({
return ( return (
<div> <div>
<NoteUpsertModal <NoteUpsertModal />
jobId={jobId}
visible={noteModalVisible}
changeVisibility={setNoteModalVisible}
refetch={refetch}
existingNote={existingNote}
/>
<Button <Button
onClick={() => { onClick={() => {
setExistingNote(null); setNoteUpsertContext({
setNoteModalVisible(true); actions: { refetch: refetch },
context: {
jobId: jobId
}
});
}} }}
> >
{t("notes.actions.new")} {t("notes.actions.new")}
@@ -125,3 +134,4 @@ export default function JobNotesComponent({
</div> </div>
); );
} }
export default connect(null, mapDispatchToProps)(JobNotesComponent);

View File

@@ -1,58 +1,41 @@
import { Input, Modal, Switch } from "antd"; import { Form, Input, Switch } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export default function NoteUpsertModalComponent({ export default function NoteUpsertModalComponent() {
visible,
changeVisibility,
noteState,
setNoteState,
updateExistingNote,
insertNewNote
}) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Modal <div>
title={noteState.id ? t("notes.actions.edit") : t("notes.actions.new")} <Form.Item
visible={visible} label={t("notes.fields.critical")}
okText={t("general.actions.save")} name="critical"
onOk={() => { valuePropName="checked"
noteState.id ? updateExistingNote() : insertNewNote(); >
}} <Switch />
onCancel={() => { </Form.Item>
changeVisibility(false); <Form.Item
}} label={t("notes.fields.private")}
> name="private"
<div> valuePropName="checked"
{t("notes.fields.critical")} >
<Switch <Switch />
title={t("notes.fields.critical")} </Form.Item>
checked={noteState.critical} <Form.Item
onChange={checked => { label={t("notes.fields.text")}
setNoteState({ ...noteState, critical: checked }); name="text"
}} rules={[
{
required: true,
message: t("general.validation.required")
}
]}
>
<Input.TextArea
rows={8}
placeholder={t("notes.labels.newnoteplaceholder")}
/> />
</div> </Form.Item>
<div> </div>
{t("notes.fields.private")}
<Switch
title={t("notes.fields.private")}
checked={noteState.private}
onChange={checked => {
setNoteState({ ...noteState, private: checked });
}}
/>
</div>
<Input.TextArea
rows={8}
value={noteState.text}
placeholder={t("notes.labels.newnoteplaceholder")}
onChange={e => {
setNoteState({ ...noteState, text: e.target.value });
}}
/>
</Modal>
); );
} }

View File

@@ -1,84 +1,97 @@
import { notification } from "antd";
import React, { useEffect, useState } from "react";
import { useMutation } from "@apollo/react-hooks"; import { useMutation } from "@apollo/react-hooks";
import { Form, Modal, notification } from "antd";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries";
import NoteUpsertModalComponent from "./note-upsert-modal.component";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectNoteUpsert } from "../../redux/modals/modals.selectors";
import { selectCurrentUser } from "../../redux/user/user.selectors"; import { selectCurrentUser } from "../../redux/user/user.selectors";
import NoteUpsertModalComponent from "./note-upsert-modal.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser currentUser: selectCurrentUser,
noteUpsertModal: selectNoteUpsert
});
const mapDispatchToProps = dispatch => ({
toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert"))
}); });
export default connect (mapStateToProps,null)( function NoteUpsertModalContainer({ export function NoteUpsertModalContainer({
jobId, currentUser,
visible, noteUpsertModal,
changeVisibility, toggleModalVisible
refetch,
existingNote,currentUser
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [insertNote] = useMutation(INSERT_NEW_NOTE); const [insertNote] = useMutation(INSERT_NEW_NOTE);
const [updateNote] = useMutation(UPDATE_NOTE); const [updateNote] = useMutation(UPDATE_NOTE);
const [noteState, setNoteState] = useState({ const { visible, context, actions } = noteUpsertModal;
private: false, const { jobId, existingNote } = context;
critical: false, const { refetch } = actions;
text: ""
}); const [form] = Form.useForm();
useEffect(() => { useEffect(() => {
//Required to prevent infinite looping. //Required to prevent infinite looping.
if (existingNote) { if (existingNote) {
setNoteState(existingNote); form.resetFields();
} }
}, [existingNote]); }, [existingNote, form]);
const insertNewNote = () => { const handleFinish = values => {
insertNote({ if (existingNote) {
variables: { updateNote({
noteInput: [ variables: {
{ ...noteState, jobid: jobId, created_by: currentUser.email } noteId: existingNote.id,
] note: values
} }
}).then(r => { }).then(r => {
refetch(); notification["success"]({
changeVisibility(!visible); message: t("notes.successes.updated")
notification["success"]({ });
message: t("notes.successes.create")
}); });
}); if (refetch) refetch();
}; toggleModalVisible();
} else {
const updateExistingNote = () => { insertNote({
//Required, otherwise unable to spread in new note prop. variables: {
delete noteState.__typename; noteInput: [
updateNote({ { ...values, jobid: jobId, created_by: currentUser.email }
variables: { ]
noteId: noteState.id, }
note: noteState }).then(r => {
} if (refetch) refetch();
}).then(r => { toggleModalVisible();
notification["success"]({ notification["success"]({
message: t("notes.successes.updated") message: t("notes.successes.create")
});
}); });
}); }
refetch();
changeVisibility(!visible);
}; };
return ( return (
<NoteUpsertModalComponent <Modal
title={existingNote ? t("notes.actions.edit") : t("notes.actions.new")}
visible={visible} visible={visible}
changeVisibility={changeVisibility} okText={t("general.actions.save")}
updateExistingNote={updateExistingNote} onOk={() => {
insertNewNote={insertNewNote} form.submit();
noteState={noteState} }}
setNoteState={setNoteState} onCancel={() => {
/> toggleModalVisible();
}}
destroyOnClose
>
<Form form={form} onFinish={handleFinish} initialValues={existingNote}>
<NoteUpsertModalComponent />
</Form>
</Modal>
); );
} }
);
export default connect(
mapStateToProps,
mapDispatchToProps
)(NoteUpsertModalContainer);

View File

@@ -11,7 +11,8 @@ const baseModal = {
const INITIAL_STATE = { const INITIAL_STATE = {
jobLineEdit: { ...baseModal }, jobLineEdit: { ...baseModal },
invoiceEnter: { ...baseModal }, invoiceEnter: { ...baseModal },
courtesyCarReturn: { ...baseModal } courtesyCarReturn: { ...baseModal },
noteUpsert: { ...baseModal }
}; };
const modalsReducer = (state = INITIAL_STATE, action) => { const modalsReducer = (state = INITIAL_STATE, action) => {

View File

@@ -17,3 +17,7 @@ export const selectCourtesyCarReturn = createSelector(
modals => modals.courtesyCarReturn modals => modals.courtesyCarReturn
); );
export const selectNoteUpsert = createSelector(
[selectModals],
modals => modals.noteUpsert
);

View File

@@ -1,5 +1,5 @@
const ModalActionTypes = { const ModalActionTypes = {
TOGGLE_MODAL_VISIBLE: "TOGGLE_MODAL_VISIBLE", TOGGLE_MODAL_VISIBLE: "TOGGLE_MODAL_VISIBLE",
SET_MODAL_CONTEXT: "SET_JOBLINEEDIT_CONTEXT" SET_MODAL_CONTEXT: "SET_MODAL_CONTEXT"
}; };
export default ModalActionTypes; export default ModalActionTypes;