diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 9336a0826..5e4230e5f 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1387,9 +1387,119 @@ notes + + actions + + + actions + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + deletenote + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + edit + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + new + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fields + + createdby + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + critical false @@ -1453,6 +1563,27 @@ + + updatedat + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + @@ -1481,6 +1612,74 @@ + + successes + + + created + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + deleted + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + updated + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + diff --git a/client/src/components/job-detail-cards/job-detail-cards.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.component.jsx index 63a0cc9cb..1aff30402 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.component.jsx @@ -20,7 +20,7 @@ import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import "./job-detail-cards.styles.scss"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; -import NoteAddModal from "../note-add-modal/note-add-modal.component"; +import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; export default function JobDetailCards({ selectedJob }) { const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, { @@ -39,7 +39,7 @@ export default function JobDetailCards({ selectedJob }) { return (
- ({ ...item }))} - rowKey="id" + rowKey='id' dataSource={joblines} onChange={handleTableChange} /> diff --git a/client/src/components/job-tombstone/job-tombstone.component.jsx b/client/src/components/job-tombstone/job-tombstone.component.jsx index 102b8f120..2f8b4b69d 100644 --- a/client/src/components/job-tombstone/job-tombstone.component.jsx +++ b/client/src/components/job-tombstone/job-tombstone.component.jsx @@ -96,7 +96,13 @@ function JobTombstone({ job, ...otherProps }) { (jobContext.owner?.last_name ?? "") : t("jobs.errors.noowner") } - tags={{jobContext?.job_status?.name}} + tags={ + + {jobContext.job_status ? ( + {jobContext.job_status.name} + ) : null} + + } extra={[ + + + ) + } + ]; + + return ( +
+ + ({ ...item }))} + rowKey='id' + dataSource={data} + /> + + ); +} diff --git a/client/src/components/note-add-modal/note-add-modal.component.jsx b/client/src/components/note-add-modal/note-add-modal.component.jsx deleted file mode 100644 index cbdfecaa7..000000000 --- a/client/src/components/note-add-modal/note-add-modal.component.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Input, Modal, Switch } from "antd"; -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useMutation } from "react-apollo"; -import { INSERT_NEW_NOTE } from "../../graphql/notes.queries"; - -export default function NoteAddModal({ - jobId, - visible, - changeVisibility, - refetch -}) { - const [newNote, setnewNote] = useState({ - private: false, - critical: false, - text: "" - }); - const { t } = useTranslation(); - const [insertNote] = useMutation(INSERT_NEW_NOTE); - - return ( - { - insertNote({ - variables: { - noteInput: [ - { ...newNote, jobid: jobId, created_by: "patrick@bodyshop.app" } - ] - } - }).then(r => { - setnewNote({ - private: false, - critical: false, - text: "" - }); - }); - console.log('refetch', refetch) - refetch(); - changeVisibility(!visible); - }} - onCancel={() => { - changeVisibility(!visible); - setnewNote({ - private: false, - critical: false, - text: "" - }); - }}> -
- {t("notes.fields.critical")} - { - setnewNote({ ...newNote, critical: checked }); - }} - /> -
-
- {t("notes.fields.private")} - { - setnewNote({ ...newNote, private: checked }); - }} - /> -
- - { - setnewNote({ ...newNote, text: e.target.value }); - }} - /> -
- ); -} diff --git a/client/src/components/note-upsert-modal/note-upsert-modal.component.jsx b/client/src/components/note-upsert-modal/note-upsert-modal.component.jsx new file mode 100644 index 000000000..3570f09f0 --- /dev/null +++ b/client/src/components/note-upsert-modal/note-upsert-modal.component.jsx @@ -0,0 +1,57 @@ +import { Input, Modal, Switch } from "antd"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +export default function NoteUpsertModalComponent({ + visible, + changeVisibility, + noteState, + setNoteState, + updateExistingNote, + insertNewNote +}) { + const { t } = useTranslation(); + + return ( + { + noteState.id ? updateExistingNote() : insertNewNote(); + }} + onCancel={() => { + changeVisibility(false); + }}> +
+ {t("notes.fields.critical")} + { + setNoteState({ ...noteState, critical: checked }); + }} + /> +
+
+ {t("notes.fields.private")} + { + setNoteState({ ...noteState, private: checked }); + }} + /> +
+ + { + setNoteState({ ...noteState, text: e.target.value }); + }} + /> +
+ ); +} diff --git a/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx new file mode 100644 index 000000000..79287a033 --- /dev/null +++ b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx @@ -0,0 +1,75 @@ +import { notification } from "antd"; +import React, { useEffect, useState } from "react"; +import { useMutation } from "react-apollo"; +import { useTranslation } from "react-i18next"; +import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries"; +import NoteUpsertModalComponent from "./note-upsert-modal.component"; + +export default function NoteUpsertModalContainer({ + jobId, + visible, + changeVisibility, + refetch, + existingNote +}) { + const { t } = useTranslation(); + const [insertNote] = useMutation(INSERT_NEW_NOTE); + const [updateNote] = useMutation(UPDATE_NOTE); + + const [noteState, setNoteState] = useState({ + private: false, + critical: false, + text: "" + }); + + useEffect(() => { + //Required to prevent infinite looping. + if (existingNote) { + setNoteState(existingNote); + } + }, [existingNote]); + + const insertNewNote = () => { + insertNote({ + variables: { + noteInput: [ + { ...noteState, jobid: jobId, created_by: "patrick@bodyshop.app" } //TODO: Fix the created by. + ] + } + }).then(r => { + notification["success"]({ + message: t("notes.successes.create") + }); + }); + refetch(); + changeVisibility(!visible); + }; + + const updateExistingNote = () => { + //Required, otherwise unable to spread in new note prop. + delete noteState.__typename; + updateNote({ + variables: { + noteId: noteState.id, + note: noteState + } + }).then(r => { + notification["success"]({ + message: t("notes.successes.updated") + }); + }); + refetch(); + changeVisibility(!visible); + }; + + return ( + + ); +} diff --git a/client/src/graphql/notes.queries.js b/client/src/graphql/notes.queries.js index 43020a900..8c3935fad 100644 --- a/client/src/graphql/notes.queries.js +++ b/client/src/graphql/notes.queries.js @@ -9,3 +9,41 @@ export const INSERT_NEW_NOTE = gql` } } `; + +export const QUERY_NOTES_BY_JOB_PK = gql` + query QUERY_NOTES_BY_JOB_PK($id: uuid!) { + jobs_by_pk(id: $id) { + id + notes { + created_at + created_by + critical + id + jobid + private + text + updated_at + } + } + } +`; + +export const UPDATE_NOTE = gql` + mutation UPDATE_NOTE($noteId: uuid!, $note: notes_set_input!) { + update_notes(where: { id: { _eq: $noteId } }, _set: $note) { + returning { + id + } + } + } +`; + +export const DELETE_NOTE = gql` + mutation DELETE_NOTE($noteId: uuid!) { + delete_notes(where: { id: { _eq: $noteId } }) { + returning { + id + } + } + } +`; diff --git a/client/src/pages/jobs-detail/jobs-detail.page.jsx b/client/src/pages/jobs-detail/jobs-detail.page.jsx index 1c814d29d..0b655d048 100644 --- a/client/src/pages/jobs-detail/jobs-detail.page.jsx +++ b/client/src/pages/jobs-detail/jobs-detail.page.jsx @@ -5,6 +5,7 @@ import JobLinesContainer from "../../components/job-lines/job-lines.container.co import JobTombstone from "../../components/job-tombstone/job-tombstone.component"; import JobsDocumentsContainer from "../../components/jobs-documents/jobs-documents.container"; import { FaRegStickyNote } from "react-icons/fa"; +import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container"; function JobsDetailPage({ jobId, hash, data, match }) { const { t } = useTranslation(); @@ -64,7 +65,7 @@ function JobsDetailPage({ jobId, hash, data, match }) { } key='#notes'> - lol notes here + diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 7eea35636..1fe0badc2 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -96,13 +96,26 @@ } }, "notes": { + "actions": { + "actions": "Actions", + "deletenote": "Delete Note", + "edit": "Edit Note", + "new": "New Note" + }, "fields": { + "createdby": "Created By", "critical": "Critical", "private": "Private", - "text": "Contents" + "text": "Contents", + "updatedat": "Updated At" }, "labels": { "newnoteplaceholder": "Add a note..." + }, + "successes": { + "created": "Note created successfully.", + "deleted": "Note deleted successfully.", + "updated": "Note updated successfully." } }, "profile": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 281590b38..217435473 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -96,13 +96,26 @@ } }, "notes": { + "actions": { + "actions": "Comportamiento", + "deletenote": "Borrar nota", + "edit": "Editar nota", + "new": "Nueva nota" + }, "fields": { + "createdby": "Creado por", "critical": "Crítico", "private": "Privado", - "text": "Contenido" + "text": "Contenido", + "updatedat": "Actualizado en" }, "labels": { "newnoteplaceholder": "Agrega una nota..." + }, + "successes": { + "created": "Nota creada con éxito.", + "deleted": "Nota eliminada con éxito.", + "updated": "Nota actualizada con éxito." } }, "profile": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 7a59df742..a3bdce8aa 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -96,13 +96,26 @@ } }, "notes": { + "actions": { + "actions": "actes", + "deletenote": "Supprimer la note", + "edit": "Note éditée", + "new": "Nouvelle note" + }, "fields": { + "createdby": "Créé par", "critical": "Critique", "private": "privé", - "text": "Contenu" + "text": "Contenu", + "updatedat": "Mis à jour à" }, "labels": { "newnoteplaceholder": "Ajouter une note..." + }, + "successes": { + "created": "Remarque créée avec succès.", + "deleted": "Remarque supprimée avec succès.", + "updated": "Remarque mise à jour avec succès." } }, "profile": {