Merge branch 'main' of github.com:kjannette/ax3Client into jdurante-1-stripe-paywall
This commit is contained in:
@@ -6,6 +6,7 @@ import Button from "../../pageElements/Button";
|
||||
import { AppContext } from "../../Hooks/useContext/appContext";
|
||||
import { AuthContext } from "../../Context/AuthProvider";
|
||||
import ProgressBar from "../../pageElements/ProgressBar";
|
||||
import ConfirmModal from "../Modals/ConfirmModal";
|
||||
|
||||
const AccountPage = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -15,7 +16,7 @@ const AccountPage = () => {
|
||||
const [docsGenerated, setDocsGenerated] = useState(null);
|
||||
const [docsAllowed, setDocsAllowed] = useState(10);
|
||||
const appUserId = group ? group.appUserId : null;
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
function getDocumentsCount() {
|
||||
if (!appUserId) {
|
||||
return;
|
||||
@@ -36,6 +37,15 @@ const AccountPage = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleCancelSub = () => {
|
||||
setShowModal(true);
|
||||
try {
|
||||
//API call(s)
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setShowModal(false);
|
||||
};
|
||||
const handleSupport = () => {
|
||||
const supReq = "5ac45d12";
|
||||
navigate(`/requestpage/${supReq}`);
|
||||
@@ -178,7 +188,11 @@ const AccountPage = () => {
|
||||
</div>
|
||||
) : null}
|
||||
<div className="account-subscriptions-actions">
|
||||
<Button className="primary-button" labelText="Cancel Account" />
|
||||
<Button
|
||||
className="primary-button cancel-sub-button"
|
||||
labelText="Cancel Subscription"
|
||||
onClick={() => setShowModal(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -194,6 +208,14 @@ const AccountPage = () => {
|
||||
<div>{telNumberFormat(group.telephone)}</div>
|
||||
</div>
|
||||
</div>
|
||||
{showModal ? (
|
||||
<ConfirmModal
|
||||
onCancel={() => setShowModal(false)}
|
||||
onConfirm={handleCancelSub}
|
||||
buttonLabelText="Confirm Cancel"
|
||||
modalText="Are you sure? Your subscription will end at the conclusion of the current billing period."
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -584,7 +584,7 @@ const DocEditPage = () => {
|
||||
const editingContent = () => {
|
||||
return (
|
||||
<>
|
||||
{headerPicker()}
|
||||
<div> {headerPicker()}</div>
|
||||
<div className="doc-editing-wrapper">
|
||||
<div className="pleading-header">{headerString}</div>
|
||||
<div>
|
||||
|
||||
@@ -171,7 +171,7 @@ const DocumentListPage = ({ perPage }) => {
|
||||
if (!group) {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("allDocs", allDocs);
|
||||
const DesktopContent = () => {
|
||||
return (
|
||||
<>
|
||||
@@ -204,6 +204,7 @@ const DocumentListPage = ({ perPage }) => {
|
||||
parentCaseNumber={doc.parentCaseNumber}
|
||||
parentCaseName={doc.parentCaseName}
|
||||
parentCaseId={doc.parentCaseId}
|
||||
createdAt={doc.createdAt}
|
||||
docType={doc.docType}
|
||||
documentId={doc.documentId}
|
||||
dateServed={doc.dateServed}
|
||||
|
||||
@@ -12,7 +12,11 @@ const NewYorkCaption = (props) => {
|
||||
<div className="docedit-uppercol2">
|
||||
<span>{fetchedCase?.jurisdiction}</span>
|
||||
<span>{fetchedCase?.venue}</span>
|
||||
<div className="docedit-uppercol-divider"></div>
|
||||
<div className="pleading-divider-box">
|
||||
<div>
|
||||
-----------------------------------------------------------------------X
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="docedit-uppercol3"></div>
|
||||
</div>
|
||||
@@ -44,7 +48,11 @@ const NewYorkCaption = (props) => {
|
||||
<div className="content-spacer2"></div>
|
||||
<div>Defendant(s)</div>
|
||||
</div>
|
||||
<div className="docedit-uppercol-divider"></div>
|
||||
<div className="pleading-divider-box">
|
||||
<div>
|
||||
----------------------------------------------------------------------------X
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="docedit-header-col3">
|
||||
<div className="scroll-button-box">
|
||||
|
||||
@@ -11,6 +11,7 @@ import { collection, setDoc, updateDoc, doc } from "firebase/firestore";
|
||||
import { AppContext } from "../../Hooks/useContext/appContext.js";
|
||||
import { db } from "../../firebase";
|
||||
import { objectMap } from "../../Utils/Object";
|
||||
import { createCaseFields as fields } from "../../Constants/Fields/CreateCaseFields.js";
|
||||
import "../../styles/modals.scss";
|
||||
import {
|
||||
getFormDataDefaults,
|
||||
@@ -28,29 +29,10 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
const appUserId = group.appUserId;
|
||||
const editCaseId = caseData?.id;
|
||||
const isEditing = typeof editCaseId !== "undefined";
|
||||
|
||||
const fields = {
|
||||
caption: { required: true, maxLength: 45 },
|
||||
captionTwo: { required: true, maxLength: 45 },
|
||||
caseNumber: { required: true, maxLength: 45 },
|
||||
judge: { required: true, maxLength: 45 },
|
||||
plaintiffParties: { required: true, maxLength: 45 },
|
||||
defendantParties: { required: true, maxLength: 45 },
|
||||
jurisdiction: { required: true, maxLength: 45 },
|
||||
billingCode: { required: true, maxLength: 45 },
|
||||
venue: { required: true, maxLength: 45 },
|
||||
caseType: { required: true, maxLength: 45 },
|
||||
trialDate: { required: true, maxLength: 45, type: "date" },
|
||||
filedDate: { required: true, maxLength: 45, type: "date" },
|
||||
contactFirstName: { required: true, maxLength: 45 },
|
||||
contactLastName: { required: true, maxLength: 45 },
|
||||
contactEmail: { required: true, maxLength: 45, type: "email" },
|
||||
leadAttorneys: { required: true, maxLength: 45 },
|
||||
lawFirm: { required: false, maxLength: 45 },
|
||||
clientPosition: { required: true, default: "Defendant" },
|
||||
};
|
||||
|
||||
const [isBusy, setIsBusy] = useState(false);
|
||||
const [newCaseId, setNewCaseId] = useState();
|
||||
const caseNumCopy =
|
||||
group.state == "New York" ? "Index Number" : "Case Number";
|
||||
const [data, setData] = useState(
|
||||
getFormDataDefaults(fields, isEditing ? caseData : undefined)
|
||||
);
|
||||
@@ -69,10 +51,8 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
return hasErrors ? null : objectMap(({ value }) => value, newData);
|
||||
};
|
||||
|
||||
async function saveCaseData() {
|
||||
const dataValues = validateData();
|
||||
|
||||
if (dataValues === null) {
|
||||
async function saveCaseData(dataValues) {
|
||||
if (isBusy) {
|
||||
return;
|
||||
}
|
||||
setIsBusy(true);
|
||||
@@ -95,6 +75,7 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
const casesRef = collection(db, "cases");
|
||||
await setDoc(doc(casesRef, `${caseId}`), caseData);
|
||||
setShowModal(false);
|
||||
return caseId;
|
||||
} catch (err) {
|
||||
console.log("Error creating case:", err);
|
||||
}
|
||||
@@ -110,11 +91,26 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreate = () => {
|
||||
if (!isBusy) {
|
||||
void saveCaseData();
|
||||
const handleCreateCaseNavigation = (caseId) => {
|
||||
// console.log("caseId in handleCreateCaseNavigation", caseId);
|
||||
};
|
||||
|
||||
const handleCreateCase = (e) => {
|
||||
e.preventDefault();
|
||||
const dataValues = validateData();
|
||||
let caseId;
|
||||
if (dataValues === null) {
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
saveCaseData(dataValues).then((res) => {
|
||||
const caseId = res;
|
||||
navigate(`/casedetails/${caseId}`);
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
navigate("/dashboard");
|
||||
};
|
||||
|
||||
const radioOptions = [
|
||||
@@ -180,7 +176,7 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
<Row>
|
||||
<Col className="mb-3">
|
||||
{isEditing ? (
|
||||
<div className="edit-modal-label">Index number</div>
|
||||
<div className="edit-modal-label">{caseNumCopy}</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
@@ -548,7 +544,7 @@ const CreateModal = ({ setShowModal, caseData }) => {
|
||||
<Button
|
||||
className="primary-button"
|
||||
disabled={isBusy}
|
||||
onClick={handleCreate}
|
||||
onClick={handleCreateCase}
|
||||
labelText="Save Case"
|
||||
/>
|
||||
</Modal.Footer>
|
||||
|
||||
@@ -42,8 +42,10 @@ const UploadModal = (props) => {
|
||||
: process.env.REACT_APP_API_PROD;
|
||||
|
||||
async function saveToDb(uuidName) {
|
||||
const createdAt = new Date();
|
||||
const data = {
|
||||
ownerId: appUserId,
|
||||
createdAt: createdAt,
|
||||
documentName: `${uuidName}.pdf`,
|
||||
docDescription: docDescription,
|
||||
dateServed: dateServed,
|
||||
@@ -124,6 +126,7 @@ const UploadModal = (props) => {
|
||||
|
||||
try {
|
||||
const response = await processFile();
|
||||
console.log("response in upload modal", response);
|
||||
if (response.res?.status !== 200) {
|
||||
saveToDb(response.uuidName);
|
||||
return;
|
||||
|
||||
@@ -262,7 +262,6 @@ const SignupPage = () => {
|
||||
<Row key={`row${j}`}>
|
||||
{names.map((name, i) => (
|
||||
<Col key={`${name}${i + fieldsChunkSize * j}`} className="mb-3">
|
||||
{console.log("data, name", data, name)}
|
||||
<TextInput
|
||||
name={name}
|
||||
value={data[name].value}
|
||||
|
||||
@@ -5,45 +5,41 @@ export const Steps = () => (
|
||||
<h2 className="doc-header-text">Generate Discovery Responses</h2>
|
||||
<ol className="steps-list">
|
||||
<li>
|
||||
<strong>CREATE THE CASE: </strong>First, input the case to which the
|
||||
discovery request pertains. Click “Cases” in the top navigation bar to
|
||||
go to the <strong>Case View</strong>. Click the “Create New Case” button
|
||||
(lower right) to surface the Create Case Modal. Enter all relevant
|
||||
information -- case name, case number, parties, etc. -- and click “Save
|
||||
Case”. The modal will close, returning you to the{" "}
|
||||
<strong>Case View.</strong>
|
||||
<strong>CREATE THE CASE: </strong> Click “Cases” in the top navigation
|
||||
bar to go to the <strong>Case View</strong>. Click the “Create New Case”
|
||||
button (lower right) to surface the Create Case Modal. Enter all
|
||||
relevant information -- case name, case number, parties, etc. -- and
|
||||
click “Save Case” to open the new case's
|
||||
<strong> Details View.</strong> Click “Upload Document”.
|
||||
</li>
|
||||
<li>
|
||||
On the newly-created case info card, click the “View” button (far right)
|
||||
to navigate to its <strong>Case Details View.</strong> Click “Upload
|
||||
Document” to surface the Document Upload Modal.
|
||||
<strong>UPLOAD YOUR DOCUMENT: </strong>You will now see the Document
|
||||
Upload Modal. Enter your discovery request's info: document title, i.e.
|
||||
“Defendant’s Interrogatories,” and (optionally) the date served. Drag
|
||||
and drop the file, or click to select it from your computer's files,{" "}
|
||||
{" "}
|
||||
then click <strong> “Upload”.</strong>
|
||||
<br /> The upload will begin. Parsing the document usually takes 1 to 2
|
||||
minutes, but be patient - it may take up to 5.
|
||||
</li>
|
||||
<li>
|
||||
<strong>UPLOAD A DOCUMENT: </strong>On the Document Upload Modal, enter
|
||||
the document title, i.e. “Defendant’s Interrogatories,” and (optionally)
|
||||
the date served. Drag and drop or click to select the request document
|
||||
from your files. <em>The document must be in .pdf format.</em>
|
||||
<br />{" "}
|
||||
<p className="howto-special-para">
|
||||
Click “Upload”, and will you automatically navigate to the Document
|
||||
List View.
|
||||
</p>{" "}
|
||||
<strong>GENERATE THE RESPONSE: </strong>From the Document List View,
|
||||
click the “Generate Responses'' button. Novdraft’s Intellidraft AI will
|
||||
generate the response and automatically navigate to the interactive
|
||||
Document Editor. You can edit the responses and save progress any time
|
||||
by clicking the “Save Changes” button.
|
||||
</li>
|
||||
<li>
|
||||
<strong>GENERATE THE DISCOVERY RESPONSE: </strong>Click the “Generate
|
||||
Responses'' button. Novdraft’s Intellidraft AI will generate the
|
||||
response and automatically navigate to the interactive Document Editor.
|
||||
You can edit the responses and save progress anytime by clicking the
|
||||
“Save Changes” button. When you are satisfied, you can download a .docx
|
||||
file by clicking the “Create .docx File” button.
|
||||
<strong>DOWNLOAD YOUR RESPONSE DOCUMENT: </strong>Click the “Create
|
||||
.Docx' button to download your fully-formatted, ready-to-serve response.
|
||||
</li>
|
||||
<ExclamationTriangle
|
||||
style={{ color: "red", marginRight: "6px", marginBottom: "2px" }}
|
||||
/>
|
||||
<strong>Pro tip:</strong> once you've created a case, you can skip most of
|
||||
these steps. Simply search for the case by entering the case number in the
|
||||
search bar on your Dashboard, click "Express Document Upload" and follow
|
||||
the prompts.
|
||||
<strong>Pro tip:</strong> Once you've created the case, you can skip step
|
||||
one. Simply search for the case by entering the case number in the search
|
||||
bar on your Dashboard, click "Express Document Upload" and follow the
|
||||
prompts.
|
||||
</ol>
|
||||
<p className="steps-p"></p>
|
||||
</div>
|
||||
|
||||
20
src/Constants/Fields/CreateCaseFields.js
Normal file
20
src/Constants/Fields/CreateCaseFields.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export const createCaseFields = {
|
||||
caption: { required: true, maxLength: 45 },
|
||||
captionTwo: { required: true, maxLength: 45 },
|
||||
caseNumber: { required: true, maxLength: 45 },
|
||||
judge: { required: true, maxLength: 45 },
|
||||
plaintiffParties: { required: true, maxLength: 45 },
|
||||
defendantParties: { required: true, maxLength: 45 },
|
||||
jurisdiction: { required: true, maxLength: 45 },
|
||||
billingCode: { required: true, maxLength: 45 },
|
||||
venue: { required: true, maxLength: 45 },
|
||||
caseType: { required: true, maxLength: 45 },
|
||||
trialDate: { required: true, maxLength: 45, type: "date" },
|
||||
filedDate: { required: true, maxLength: 45, type: "date" },
|
||||
contactFirstName: { required: true, maxLength: 45 },
|
||||
contactLastName: { required: true, maxLength: 45 },
|
||||
contactEmail: { required: true, maxLength: 45, type: "email" },
|
||||
leadAttorneys: { required: true, maxLength: 45 },
|
||||
lawFirm: { required: false, maxLength: 45 },
|
||||
clientPosition: { required: true, default: "Plaintiff" },
|
||||
};
|
||||
@@ -96,8 +96,10 @@ export const handleFormDataChange = (e, name, data, fields) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export const isFormDataHasErrors = (data) =>
|
||||
Object.values(data).reduce(
|
||||
export const isFormDataHasErrors = (data) => {
|
||||
console.log("data", data);
|
||||
return Object.values(data).reduce(
|
||||
(hasErrors, { error }) => hasErrors || error,
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import { FileEarmarkText } from "react-bootstrap-icons";
|
||||
import TextInput from "../pageElements/TextInput";
|
||||
import Tooltip from "../pageElements/Tooltip";
|
||||
import { InfoCircle } from "react-bootstrap-icons";
|
||||
|
||||
import { toDate } from "firebase/firestore";
|
||||
export const InfoCard = (props) => {
|
||||
const { data, onEdit, onCancel, onSave, onChangeInput, isEditing, isBusy } =
|
||||
props;
|
||||
@@ -273,15 +273,20 @@ export const DocCard = (props) => {
|
||||
handleNavigate,
|
||||
responseGenerations,
|
||||
confirmDelete,
|
||||
createdAt,
|
||||
} = props;
|
||||
|
||||
const now = new Date().getTime();
|
||||
const uploadedAt = createdAt.toDate();
|
||||
const isReportable = Math.round((now - uploadedAt) / 60 / 1000) > 15;
|
||||
const disabled = docType ? false : true;
|
||||
const tooltipText =
|
||||
"Parsing is taking a bit longer than usual. This usually resolves within 15 minutes. If it does not, click “report” and support will address the issue within 24 hours.";
|
||||
const pendingText =
|
||||
"Parsing in process, please be patient. This should resolve within 10 minutes.";
|
||||
const report = (documentId, docType) => {
|
||||
console.log("report documentId, docType", documentId, docType);
|
||||
};
|
||||
|
||||
const tooltipText =
|
||||
"Parsing is taking a bit longer than usual. This usually resolves within 10 - 15 minutes. If it does not, click “report” and support will address the issue within 24 hours.";
|
||||
const disabled = docType ? false : true;
|
||||
return (
|
||||
<div className="doc-card-container">
|
||||
<div className="doc-card-input">
|
||||
@@ -289,7 +294,13 @@ export const DocCard = (props) => {
|
||||
<FileEarmarkText className="doc-file-icon" size="22px" />
|
||||
</div>
|
||||
<div className="doc-col2">
|
||||
{title} {disabled ? <Tooltip text={tooltipText} /> : <></>}
|
||||
{title}{" "}
|
||||
{disabled && isReportable ? <Tooltip text={tooltipText} /> : <></>}
|
||||
{disabled && !isReportable ? (
|
||||
<Tooltip text={pendingText} iconStyle="clock" />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
{dateServed ? (
|
||||
<div className="doc-col3">Served: {dateServed}</div>
|
||||
@@ -299,7 +310,7 @@ export const DocCard = (props) => {
|
||||
<div className="doc-col4">
|
||||
<div className="jurisdiction-box">{parentCaseName}</div>
|
||||
</div>
|
||||
{disabled ? (
|
||||
{disabled && isReportable ? (
|
||||
<div className="doc-col5">
|
||||
<Button
|
||||
labelText="Report"
|
||||
@@ -345,3 +356,17 @@ export const DocCard = (props) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
{disabled ? (
|
||||
isReportable ? (
|
||||
<Tooltip text={tooltipText} />
|
||||
) : (
|
||||
<Tooltip text={pendingText} iconStyle="clock" />
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { useState } from "react";
|
||||
import "../styles/tooltip.scss";
|
||||
import { InfoCircle } from "react-bootstrap-icons";
|
||||
import { InfoCircle, Clock } from "react-bootstrap-icons";
|
||||
|
||||
function Tooltip(props) {
|
||||
const [show, setShow] = useState(false);
|
||||
const { text } = props;
|
||||
const [showMessage, setShowMessage] = useState(false);
|
||||
const { text, iconStyle } = props;
|
||||
const showClock = iconStyle === "clock";
|
||||
return (
|
||||
<div
|
||||
className="tooltip-container"
|
||||
onMouseEnter={() => setShow(true)}
|
||||
onMouseLeave={() => setShow(false)}
|
||||
onMouseEnter={() => setShowMessage(true)}
|
||||
onMouseLeave={() => setShowMessage(false)}
|
||||
>
|
||||
{showClock ? (
|
||||
<Clock className="infocircle-icon" size="16px" />
|
||||
) : (
|
||||
<InfoCircle className="infocircle-icon" size="16px" />
|
||||
{show ? <span className="tooltip-text">{text}</span> : <></>}
|
||||
)}
|
||||
{showMessage ? <span className="tooltip-text">{text}</span> : <></>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,6 +87,10 @@ $account-support-title-padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-sub-button {
|
||||
width: 165px;
|
||||
}
|
||||
|
||||
.account-support {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
.docedit-header-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 210px;
|
||||
height: 230px;
|
||||
margin-bottom: 12px;
|
||||
color: #000000;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
@@ -247,7 +248,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 60%;
|
||||
margin: 22px auto;
|
||||
margin: 6px auto;
|
||||
color: #4e4e4e;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user