Merge pull request #179 from kjannette/analy

Analy
This commit is contained in:
S Jannette
2024-03-23 03:08:04 -05:00
committed by GitHub
10 changed files with 680 additions and 388 deletions

View File

@@ -1,5 +1,10 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { checkActionCode, confirmPasswordReset, getAuth, sendPasswordResetEmail } from "firebase/auth"; import {
checkActionCode,
confirmPasswordReset,
getAuth,
sendPasswordResetEmail,
} from "firebase/auth";
import Button from "../../pageElements/Button"; import Button from "../../pageElements/Button";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
@@ -75,122 +80,133 @@ const PasswordResetPage = () => {
} finally { } finally {
setIsBusy(false); setIsBusy(false);
} }
} };
const resetMode = mode === "resetPassword" ? "resetPassword" : "enterEmail"; const resetMode = mode === "resetPassword" ? "resetPassword" : "enterEmail";
return ( return (
<div className="password-reset-container"> <div className="password-reset-container">
<div className="password-reset-form-wrapper"> <div className="password-reset-form-wrapper">
<div className="password-reset-form"> <div className="password-reset-form">
{resetMode === "enterEmail" ? <> {resetMode === "enterEmail" ? (
<div className="password-reset-header"> <>
<h2 className="password-reset-header-text"> <div className="password-reset-header">
Enter Account Email <h2 className="password-reset-header-text">
</h2> Enter Account Email
</div> </h2>
{!done ? (
<form>
<div className="form-floating">
<input
type="email"
className="form-control"
id="emailInput"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={isBusy}
></input>
<label htmlFor="emailInput" className="form-label">
Email
</label>
</div>
<div className="alert-box">
{"" !== notice && (
<div className="password-reset-alert" role="alert">
{notice}
</div>
)}
</div>
<div className="password-reset-button-wrapper">
<Button
className="primary-button"
onClick={(e) => handleResetPassword(e)}
labelText="Submit"
disabled={isBusy}
/>
</div>
</form>
) : null}
{done && (
<div className="success-container">
<p className="reset-sent-text">A password reset link was sent.</p>
</div> </div>
)} {!done ? (
</> : null} <form>
{resetMode === "resetPassword" ? <> <div className="form-floating">
<div className="password-reset-header"> <input
<h2 className="password-reset-header-text"> type="email"
Enter New Password className="form-control"
</h2> id="emailInput"
</div> placeholder="Email"
{!done && isCodeValid !== null && isCodeValid ? ( value={email}
<form> onChange={(e) => setEmail(e.target.value)}
<div className="form-floating mb-3"> disabled={isBusy}
<input ></input>
type="password" <label htmlFor="emailInput" className="form-label">
className="form-control" Email
id="passwordInput" </label>
placeholder="Password" </div>
value={password} <div className="alert-box">
onChange={(e) => setPassword(e.target.value)} {"" !== notice && (
disabled={isBusy} <div className="password-reset-alert" role="alert">
></input> {notice}
<label htmlFor="emailInput" className="form-label"> </div>
Enter new password )}
</label> </div>
<div className="password-reset-button-wrapper">
<Button
className="primary-button"
onClick={(e) => handleResetPassword(e)}
labelText="Submit"
disabled={isBusy}
/>
</div>
</form>
) : null}
{done && (
<div className="success-container">
<p className="reset-sent-text">
A password reset link was sent.
</p>
</div> </div>
<div className="form-floating"> )}
<input </>
type="password" ) : null}
className="form-control" {resetMode === "resetPassword" ? (
id="confirmPasswordInput" <>
placeholder="Confirm Password" <div className="password-reset-header">
value={confirmPassword} <h2 className="password-reset-header-text">
onChange={(e) => setConfirmPassword(e.target.value)} Enter New Password
disabled={isBusy} </h2>
></input>
<label htmlFor="confirmPasswordInput" className="form-label">
Confirm password
</label>
</div>
<div className="alert-box">
{"" !== notice && (
<div className="password-reset-alert" role="alert">
{notice}
</div>
)}
</div>
<div className="password-reset-button-wrapper">
<Button
className="primary-button"
onClick={(e) => handleConfirmPasswordReset(e)}
labelText="Submit"
disabled={isBusy}
/>
</div>
</form>
) : null}
{!done && isCodeValid !== null && !isCodeValid && (
<div className="success-container">
<p className="reset-sent-text">Bad or already used password reset code.</p>
</div> </div>
)} {!done && isCodeValid !== null && isCodeValid ? (
{done && ( <form>
<div className="success-container"> <div className="form-floating mb-3">
<p className="reset-sent-text">Password changed.</p> <input
</div> type="password"
)} className="form-control"
</> : null} id="passwordInput"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={isBusy}
></input>
<label htmlFor="emailInput" className="form-label">
Enter new password
</label>
</div>
<div className="form-floating">
<input
type="password"
className="form-control"
id="confirmPasswordInput"
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
disabled={isBusy}
></input>
<label
htmlFor="confirmPasswordInput"
className="form-label"
>
Confirm password
</label>
</div>
<div className="alert-box">
{"" !== notice && (
<div className="password-reset-alert" role="alert">
{notice}
</div>
)}
</div>
<div className="password-reset-button-wrapper">
<Button
className="primary-button"
onClick={(e) => handleConfirmPasswordReset(e)}
labelText="Submit"
disabled={isBusy}
/>
</div>
</form>
) : null}
{!done && isCodeValid !== null && !isCodeValid && (
<div className="success-container">
<p className="reset-sent-text">
Bad or already used password reset code.
</p>
</div>
)}
{done && (
<div className="success-container">
<p className="reset-sent-text">Password changed.</p>
</div>
)}
</>
) : null}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -83,6 +83,7 @@ const CaseListPage = ({ perPage }) => {
</div> </div>
); );
}; };
const dropDownOptions = [ const dropDownOptions = [
{ label: "Case name a - z", value: "caption" }, { label: "Case name a - z", value: "caption" },
{ label: "Case name z - a", value: "caption2" }, { label: "Case name z - a", value: "caption2" },
@@ -159,11 +160,17 @@ const CaseListPage = ({ perPage }) => {
</> </>
) : ( ) : (
<div className="nodocs-text-container"> <div className="nodocs-text-container">
<p> You have not created any cases yet.</p> <p> Please create your first case.</p>
<p> <p>
To get started, click "Create New Case" and enter case To create a discovery request or response, you will first enter
information. some basic information about the case they will pertain to -
i.e. the caption and case number.
</p> </p>
<p>
Then, you will upload a document (i.e. interrogatories or a
complaint), for use in generating a request/response.
</p>
<p>Click "Create New Case" to get started.</p>
{createNewButton()} {createNewButton()}
</div> </div>
) )

View File

@@ -15,21 +15,26 @@ import { Typeahead } from "react-bootstrap-typeahead";
import { AppContext } from "../../Hooks/useContext/appContext.js"; import { AppContext } from "../../Hooks/useContext/appContext.js";
import UploadModal from "../Modals/UploadModal.js"; import UploadModal from "../Modals/UploadModal.js";
import Button from "react-bootstrap/Button"; import Button from "react-bootstrap/Button";
import { getAuth } from "firebase/auth";
const Dashboard = () => { const Dashboard = () => {
const size = window.innerWidth < 440; const size = window.innerWidth < 440;
const [isMobile, setIsMobile] = useState(size); const [isMobile, setIsMobile] = useState(size);
const auth = getAuth();
const count = useRef(null); const count = useRef(null);
const navigate = useNavigate(); const navigate = useNavigate();
const [allCases, setAllCases] = useState(null); const [allCases, setAllCases] = useState(null);
const [selectedCase, setSelectedCase] = useState(null); const [selectedCase, setSelectedCase] = useState(null);
const [showModal, setShowModal] = useState(); const [showModal, setShowModal] = useState();
const [docCount, setDocCount] = useState(); const [docCount, setDocCount] = useState();
const [isPromoFirstLogin, setIsPromoFirstLogin] = useState(true);
const [responseCount, setResponseCount] = useState(); const [responseCount, setResponseCount] = useState();
const { appState } = useContext(AppContext); const { appState } = useContext(AppContext);
const { group } = appState; const { group } = appState;
const appUserId = group ? group.appUserId : null; const appUserId = group ? group.appUserId : null;
const isDashboard = true; const isDashboard = true;
console.log("group on dashbaord page", group);
console.log("auth in dashoabrd page", auth);
useEffect(() => { useEffect(() => {
if (count.current == null) { if (count.current == null) {
@@ -177,6 +182,31 @@ const Dashboard = () => {
<div className="user-name-container2">{group.firm}</div> <div className="user-name-container2">{group.firm}</div>
</div> </div>
<div className="app-divider dash-divider" /> <div className="app-divider dash-divider" />
{isPromoFirstLogin ? (
<>
<div className="dash-promo-first-box">
<div className="dash-promo-first-wrap">
<div className="dash-promo-first-textwrap">
<div className="dash-promo-first-text">
Welcome to Novodraft, attorney {group.lastName}. We are
excited to introduce you to our application. Review the
step-by-step user guide by clicking "How-to" in the navigation
bar.
</div>
<div className="dash-promo-first-text">
Your user name for login is:{" "}
<span className="user-name-span">{group.email}</span>. Your
temporary password is{" "}
<span className="user-name-span">{group.tpe}</span>. You
should change it now, by clicking here.
</div>
</div>
</div>
</div>
<div className="app-divider dash-divider" />
</>
) : null}
<div className="stats-container"> <div className="stats-container">
<div className="stats-row-box"> <div className="stats-row-box">
<div className="stats-unit-wrapper"> <div className="stats-unit-wrapper">

View File

@@ -1,284 +1,478 @@
import { useEffect } from "react"; import { useEffect, useState } from "react";
import { collection, setDoc, doc } from "firebase/firestore"; import { collection, setDoc, doc } from "firebase/firestore";
import { db } from "../../firebase"; import { db, auth } from "../../firebase";
import Button from "../../pageElements/Button"; import Button from "../../pageElements/Button";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import arrow from "../../Assets/Images/Arrow.png"; import arrow from "../../Assets/Images/Arrow.png";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import ConfirmModal from "../Modals/ConfirmModal";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { stateDataValues } from "../../Constants/Fields/SignupFields";
import "../../styles/homepage.scss"; import "../../styles/homepage.scss";
import LoadingSpinner from "../../pageElements/LoadingSpinner";
const HomePage = () => { const HomePage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [showPromoModal, setShowPromoModal] = useState(false);
const [isBusy, setIsBusy] = useState(false);
const [notice, setNotice] = useState("");
const handleNavigate = () => { const apiUrl =
navigate("/signup"); process.env.NODE_ENV === "development"
? process.env.REACT_APP_API_DEV
: process.env.REACT_APP_API_PROD;
async function saveUserData(
authId,
dataValues,
email,
password,
customerId,
subscriptionCreated,
subscriptionPeriodStart,
subscriptionPeriodEnd,
subscriptionId,
isPromotionalMebership = true,
docsAllowedPeMonth = 1
) {
if (!email || !password || !dataValues[0]) {
return;
}
const appUserId = uuidv4();
const firmId = uuidv4();
const fbAuthUid = authId;
const tpe = password;
let plan = "promo plan";
let docsAllowedPerMonth;
docsAllowedPerMonth = 1;
subscriptionId = uuidv4();
plan = plan;
const docsGenerated = 0;
const {
firstName,
lastName,
firm,
telephone,
streetAddress,
city,
state,
zipCode,
barNumber,
practiceArea,
} = dataValues[0];
const userState = stateDataValues.filter((value) => {
if (value.name === state) return value;
});
const userData = {
docsAllowedPerMonth,
docsGenerated,
appUserId,
fbAuthUid,
firmId,
firstName,
lastName,
firm,
telephone,
streetAddress,
city,
state: userState,
zipCode,
barNumber,
practiceArea,
email,
tpe: tpe,
isPromotionalMebership,
isPromotionalFirstLogin: true,
customerId: customerId,
subscriptionId: subscriptionId,
subscriptionPlan: "flordia-spring-promo-plan",
subscriptionCreated: subscriptionCreated,
subscriptionPeriodStart: subscriptionPeriodStart,
subscriptionPeriodEnd: subscriptionPeriodEnd,
};
try {
const usersRef = collection(db, "users");
const res = await setDoc(doc(usersRef, fbAuthUid), userData);
return res;
} catch (error) {
console.log(`Error saving new user to db: ${error}`);
}
}
async function getFocusData(code) {
console.log("code in getFocusData", code);
try {
const response = await fetch(`${apiUrl}/v1/get-focused-data/${code}`, {
method: "GET",
});
const res = await response.json();
console.log("res in getFocusData", res);
return res;
} catch (err) {
console.log("Error in get rqst:", err);
}
}
async function handleProcessPromoSubscription(code) {
console.log("code in handleProcessPromoSubscription", code);
setIsBusy(true);
setShowPromoModal(false);
if (!code) {
return;
}
const userData = await getFocusData(code);
console.log("userData in returned from getFocusData", userData);
const email = userData[0].email;
const password = userData[0].password;
if (email && password) {
console.log("123 email, password", email, password);
handlePromoSignup(userData, email, password);
}
}
async function handlePromoSignup(dataValues, email, password) {
if (!email || !password) {
return;
}
try {
const customerId = `${uuidv4()}-florida-spring-promo`;
const today = new Date();
const subscriptionCreated = today;
const subscriptionPeriodStart = today;
console.log("subscriptionPeriodStart", subscriptionPeriodStart);
const subscriptionPeriodEnd = today;
const subscriptionId = uuidv4();
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
dataValues = { ...dataValues };
const isPromotionalMebership = true;
console.log("userCredential", userCredential);
const res = await saveUserData(
user.uid,
dataValues,
email,
password,
customerId,
subscriptionCreated,
subscriptionPeriodStart,
subscriptionPeriodEnd,
subscriptionId,
isPromotionalMebership
);
console.log("res from saveUserData in handlePromoSignup", res);
setIsBusy(false);
navigate("/dashboard");
} catch (error) {
console.log("Error handling request", error, error.message);
setIsBusy(false);
setNotice("Sorry, something went wrong. Please try again.");
}
}
const handleTryItButton = () => {
setShowPromoModal(true);
}; };
const handleLogin = () => { const handleLogin = () => {
navigate("/login"); navigate("/login");
}; };
const handleCancelModal = () => {
setShowPromoModal(!showPromoModal);
navigate("/signup");
};
const handleDemo = () => { const handleDemo = () => {
const supReq = null; const supReq = null;
navigate("/requestpage/supReq"); navigate("/requestpage/supReq");
}; };
return ( const homeContent = (
<> <div className="homepage-container">
<div className="homepage-container"> <section
<section className="section-1"
className="section-1" style={{
backgroundImage: `url(https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/ee5222a0-7480-43ba-0f14-0ea482f31300/public)`,
backgroundSize: "cover",
}}
>
<div className="first-section-subcontainer">
<div className="row upper-row-one">
<div className="col-md-12 mobile-col-up">
<div className="heading-one-container">
<h1 className="heading-1">Novodraft: Legal AI</h1>
<h1 className="heading-1-mobile">Novodraft</h1>
<h1 className="heading-2-mobile">AI-Assisted Legal Drafting</h1>
<h1 className="heading-2">
Draft documents faster <i>and </i> smarter
</h1>
</div>
<div className="mobile-lower-header-1">
<div className="mobile-lower-header-top">
<div className="mobile-sw-deck">Discovery requests</div>
<div className="mobile-sw-deck"> dramatically fast</div>
<div className="mobile-sw-reptwo">
<div className="ex-arca-two">Draft responses to</div>
<div className="ex-arca-two">demands in minutes</div>
</div>
</div>
<div className="mobile-lower-header-bottom">
<div className="mobile-lower-header-bottom-up"></div>
<div className="mobile-lower-header-bottom-down">
<Button
className="primary-button homepage-button"
labelText="Try It For Free"
onClick={handleTryItButton}
/>
</div>
</div>
</div>
<p className="text-block-1">
Discovery requests done dramatically fast discovery responses
ready in minutes.
</p>
<p className="text-block-two">
Reclaim hours every week. Spend time growing your practice, or
just get home by dinner.
</p>
<div className="try-it-button-box">
<Button
className="primary-button homepage-button"
labelText="Try It For Free"
onClick={handleTryItButton}
/>
</div>
</div>
</div>
</div>
</section>
{/* Section 2 */}
<section className="section-2">
<div className="home-row">
<div className="home-col-50">
<div className="heading-2-mobile-box">
<h2 className="heading-2-mobile">
Made by Attorneys, for Attorneys
</h2>
</div>
<div className="pad-2">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/5f0f6f11-bb56-4f03-b05e-189d4f1a5600/public"
alt="image of a laptop computer"
className="img-2"
/>
</div>
</div>
<div className="home-col-50">
<div className="pad-2">
<h2 className="heading-2">Made by Attorneys, for Attorneys.</h2>
<div className="text-block-2-box">
<p className="text-block-2">
Legal tech developed by people that understand what you need.
</p>
</div>
<p className="section-two-body">
Novodraft understands the demands on your time. For example,
that discovery request on your desk. With a few clicks, and
Novodraft's AI assistant on the task, you can draft a
ready-to-serve response in minutes. It's as easy as uploading a
.pdf file.
</p>
<p className="section-two-body">
Novodraft cuts through a mire of rote tasks, but does much more
than automate.
</p>
<p className="section-two-body">
Intellidraft AI technology powers persuasive arguments and
boosts bland, boilerplate objections. Configurable for level of
authoritative citation and for infering factual context from
pleadings and briefs. Use it to augment your drafting as much or
as little as you prefer.
</p>
<div className="home-link-box">
<a className="link">
Explore Novodraft
<img src={arrow} className="img-1" alt="" />
</a>
</div>
</div>
</div>
</div>
</section>
{/* Section 3 */}
<section className="section-3">
<div className="section-three-header-box">
<h2 className="section-three-header">
AI-Powered Legal Drafting Technology{" "}
</h2>
<h2 className="section-three-header-mobile">
Novo Drafting Technology
</h2>
<p className="section-three-subhead">
Created by litigators to give you an edge.
</p>
</div>
<div className="card-section-container">
{/*********** CARD ONE *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/5ff0ba9e-298f-4ee1-88d4-e19a44a00900/public"
alt="ai hand"
width="100%"
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Discovery Requests</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Generate interrogatories and requests for
production/admissions leveraging AI.
</p>
<p className="card-texts">
Edit or add special language with tags. Concise yet
comprehensive demands, done in minutes.
</p>
</div>
</div>
</div>
{/*********** CARD TWO *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/7a6dd50e-4d8f-4068-61b2-634dc5603f00/public"
alt="scales image"
width="100%"
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Discovery Responses</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Use Novodraft AI to quickly draft responses including
compelling arguments about what you withhold from disclosure.
Finish in minutes with a downloadable .docx file.
</p>
</div>
</div>
</div>
{/*********** CARD THREE *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/00667aa1-f847-430c-7a5e-d96abeed3300/public"
alt=""
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Proactive Alerts</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Your dashboard displays important deadlines, alerts, and can
be configured to auto-draft documents with reminders for tasks
such as service or hearings.
</p>
</div>
</div>
</div>
</div>
</section>
<section className="section-5 py-5">
<div
className="home-test-container"
style={{ style={{
backgroundImage: `url(https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/ee5222a0-7480-43ba-0f14-0ea482f31300/public)`, backgroundImage: `url(https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/209dcf14-c086-42b4-ca72-f058d9ad1b00/public)`,
backgroundSize: "cover", backgroundSize: "cover",
}} }}
> >
<div className="first-section-subcontainer"> <div className="row">
<div className="row upper-row-one"> <div className="col-md-6">
<div className="col-md-12 mobile-col-up"> <div className="bottom-header-box">
<div className="heading-one-container"> <h4 className="heading-6">
<h1 className="heading-1">Novodraft: Legal AI.</h1> Questions about our services? <br></br>
<h1 className="heading-1-mobile">Novodraft</h1> We're here to answer!
<h1 className="heading-2-mobile"> </h4>
AI-Assisted Legal Drafting <h4 className="heading-6-mobile">
</h1> Questions about our products and services?
<h1 className="heading-2"> </h4>
Draft documents faster <i>and </i> smarter. <h4 className="heading-6-mobile">We're here to answer!</h4>
</h1>
</div>
<div className="mobile-lower-header-1">
<div className="mobile-lower-header-top">
<div className="mobile-sw-deck">Discovery requests</div>
<div className="mobile-sw-deck"> dramatically fast</div>
<div className="mobile-sw-reptwo">
<div className="ex-arca-two">Draft responses to</div>
<div className="ex-arca-two">demands in minutes</div>
</div>
</div>
<div className="mobile-lower-header-bottom">
<div className="mobile-lower-header-bottom-up"></div>
<div className="mobile-lower-header-bottom-down">
<Button
className="primary-button homepage-button"
labelText="Try It For Free"
onClick={handleNavigate}
/>
</div>
</div>
</div>
<p className="text-block-1">
Discovery requests done dramatically fast discovery
responses ready in minutes
</p>
<p className="text-block-two">
Reclaim hours every week. Spend time growing your practice, or
just get home by dinner.
</p>
<div className="try-it-button-box">
<Button
className="primary-button homepage-button"
labelText="Try It For Free"
onClick={handleNavigate}
/>
</div>
</div> </div>
<h6 className="join-heading">
Novodraft will revolutionize your practice.
</h6>
<h6 className="join-heading">
Request a demo - let us show you how.
</h6>
<h6 className="join-heading-mobile">
Revolutionize your practice.
</h6>
<h6 className="join-heading-mobile">Let us show you how.</h6>
</div>
<div className="col-md-6 d-flex">
<button className="button-2" onClick={handleDemo}>
Request a demo
</button>
<button className="button-2" onClick={handleLogin}>
Go to login
</button>
</div> </div>
</div> </div>
</section> </div>
{/* Section 2 */} </section>
<section className="section-2"> {showPromoModal ? (
<div className="home-row"> <ConfirmModal
<div className="home-col-50"> titleText="Enter Promo Code"
<div className="heading-2-mobile-box"> onCancel={handleCancelModal}
<h2 className="heading-2-mobile"> buttonLabelText="Enter Code"
Made by Attorneys, for Attorneys isPromoModal={true}
</h2> onConfirm={handleProcessPromoSubscription}
</div> cancelButtonText="I don't have a code"
/>
) : (
<></>
)}
</div>
);
<div className="pad-2"> return isBusy ? (
<img <LoadingSpinner message={""} loaderType="MoonLoader" />
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/5f0f6f11-bb56-4f03-b05e-189d4f1a5600/public" ) : (
alt="image of a laptop computer" homeContent
className="img-2"
/>
</div>
</div>
<div className="home-col-50">
<div className="pad-2">
<h2 className="heading-2">Made by Attorneys, for Attorneys</h2>
<div className="text-block-2-box">
<p className="text-block-2">
Legal tech built by people that get it.
</p>
</div>
<p className="section-two-body">
Novodraft understands the demands on your time. For example,
that discovery request on your desk. With a few clicks, and
Novodraft's AI assistant on the task, you can draft a
ready-to-serve response in minutes. It's as easy as uploading
a .pdf file.
</p>
<p className="section-two-body">
Novodraft cuts through a mire of rote tasks, but does much
more than automate.
</p>
<p className="section-two-body">
Intellidraft AI technology powers persuasive arguments and
boosts bland, boilerplate objections. Configurable for level
of authoritative citation and for infering factual context
from pleadings and briefs. Use it to augment your drafting as
much or as little as you prefer.
</p>
<div className="home-link-box">
<a className="link">
Explore Novodraft
<img src={arrow} className="img-1" alt="" />
</a>
</div>
</div>
</div>
</div>
</section>
{/* Section 3 */}
<section className="section-3">
<div className="section-three-header-box">
<h2 className="section-three-header">
AI-Powered Legal Drafting Technology{" "}
</h2>
<h2 className="section-three-header-mobile">
Novo Drafting Technology
</h2>
<p className="section-three-subhead">
Created by litigators to give you an edge.
</p>
</div>
<div className="card-section-container">
{/*********** CARD ONE *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/5ff0ba9e-298f-4ee1-88d4-e19a44a00900/public"
alt="ai hand"
width="100%"
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Discovery Requests</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Generate discovery requests with AI at your service, edit or
add special language with tags. Concise yet comprehensive
demands, done in minutes and downloadable as .docx.
</p>
</div>
</div>
</div>
{/*********** CARD TWO *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/7a6dd50e-4d8f-4068-61b2-634dc5603f00/public"
alt="scales image"
width="100%"
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Discovery Responses</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Novodraft's AI powers responses with compelling arguments
about what you choose to disclose and withhold. You'll
finish in minutes with a downloadable .docx file.
</p>
</div>
</div>
</div>
{/*********** CARD THREE *********** */}
<div className="home-card">
<div className="card-image-container">
<img
src="https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/00667aa1-f847-430c-7a5e-d96abeed3300/public"
alt=""
className="card-image"
/>
</div>
<div className="card-body">
<div className="card-upper-box">
<div className="home-card-title">
<h3 className="foo-card-title">Proactive Alerts</h3>
<div className="home-card-divider"></div>
</div>
</div>
<div className="home-card-text-box">
<p className="card-texts">
Your dashboard displays important deadlines, alerts, and can
configure to auto-draft documents and remind you to serve
them.
</p>
</div>
</div>
</div>
</div>
</section>
<section className="section-5 py-5">
<div
className="home-test-container"
style={{
backgroundImage: `url(https://imagedelivery.net/OvFc3s8IYmBw7-_bogeTLg/209dcf14-c086-42b4-ca72-f058d9ad1b00/public)`,
backgroundSize: "cover",
}}
>
<div className="row">
<div className="col-md-6">
<div className="bottom-header-box">
<h4 className="heading-6">
Questions about our services? <br></br>
We're here to answer!
</h4>
<h4 className="heading-6-mobile">
Questions about our products and services?
</h4>
<h4 className="heading-6-mobile">We're here to answer!</h4>
</div>
<h6 className="join-heading">
Novodraft will revolutionize your practice.
</h6>
<h6 className="join-heading">
Request a demo - let us show you how.
</h6>
<h6 className="join-heading-mobile">
Revolutionize your practice.
</h6>
<h6 className="join-heading-mobile">Let us show you how.</h6>
</div>
<div className="col-md-6 d-flex">
<button className="button-2" onClick={handleDemo}>
Request a demo
</button>
<button className="button-2" onClick={handleLogin}>
Go to login
</button>
</div>
</div>
</div>
</section>
</div>
</>
); );
}; };

View File

@@ -22,6 +22,7 @@ const ConfirmModal = ({
isPromoModal, isPromoModal,
cancelButtonText, cancelButtonText,
}) => { }) => {
const [inputValue, setInputValue] = useState("");
const title = titleText ? titleText : "Confirmation"; const title = titleText ? titleText : "Confirmation";
return ( return (
@@ -53,11 +54,11 @@ const ConfirmModal = ({
<TextInput <TextInput
key={"captionTwo"} key={"captionTwo"}
name={"captionTwo"} name={"captionTwo"}
value={issueText} value={inputValue}
message={"data.captionTwo.message"} message={"data.captionTwo.message"}
onChange={(e) => setIssueText(e.target.value)} onChange={(e) => setInputValue(e.target.value)}
label={ label={
issueText inputValue
? "" ? ""
: isPromoModal : isPromoModal
? "Enter your promotional code" ? "Enter your promotional code"
@@ -79,7 +80,7 @@ const ConfirmModal = ({
<Button <Button
disabled={isBusy} disabled={isBusy}
className="primary-button" className="primary-button"
onClick={onConfirm} onClick={() => onConfirm(inputValue)}
labelText={buttonLabelText} labelText={buttonLabelText}
/> />
</Modal.Footer> </Modal.Footer>

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState } from "react";
import Col from "react-bootstrap/Col"; import Col from "react-bootstrap/Col";
import Form from "react-bootstrap/Form"; import Form from "react-bootstrap/Form";
import Row from "react-bootstrap/Row"; import Row from "react-bootstrap/Row";
@@ -75,9 +75,9 @@ const SignupPage = () => {
} }
}; };
const handleConfirmPromoCode = () => { const handleConfirmPromoCode = (code) => {
if (issueText === marchEmailPrm) { if (code === marchEmailPrm) {
handlePromoSignup(); handlePromoSignup(code);
} }
}; };
@@ -467,7 +467,7 @@ const SignupPage = () => {
} }
}; };
const handlePromoSignup = async () => { const handlePromoSignup = async (code) => {
let dataValues = validateUserData(); let dataValues = validateUserData();
if (dataValues === null) { if (dataValues === null) {
return; return;
@@ -540,7 +540,8 @@ const SignupPage = () => {
<h1 className="signup-header-text">Create A Novodraft Account</h1> <h1 className="signup-header-text">Create A Novodraft Account</h1>
{!isUpgrade ? ( {!isUpgrade ? (
<h5 className="signup-header-text trial"> <h5 className="signup-header-text trial">
Start a free trial - save hours and draft smarter discovery Create an account to start a free trial - save time and draft
smarter
</h5> </h5>
) : ( ) : (
<></> <></>

View File

@@ -2,7 +2,13 @@ import React, { createContext, useContext, useEffect, useReducer } from "react";
import { useGroupReducer } from "../useReducer/reducers"; import { useGroupReducer } from "../useReducer/reducers";
import { AuthContext } from "../../Context/AuthProvider"; import { AuthContext } from "../../Context/AuthProvider";
import { db } from "../../firebase.js"; import { db } from "../../firebase.js";
import { collection, getDocs, query, where, onSnapshot } from "firebase/firestore"; import {
collection,
getDocs,
query,
where,
onSnapshot,
} from "firebase/firestore";
const initialState = { const initialState = {
group: undefined, group: undefined,
@@ -16,9 +22,9 @@ const AppContext = createContext({
const AppProvider = ({ children }) => { const AppProvider = ({ children }) => {
const { currentUserEmail } = useContext(AuthContext); const { currentUserEmail } = useContext(AuthContext);
const [appState, appDispatch] = useReducer(useGroupReducer, initialState); const [appState, appDispatch] = useReducer(useGroupReducer, initialState);
console.log("currentUserEmail in AppProvider", currentUserEmail);
useEffect(() => { useEffect(() => {
if (typeof currentUserEmail === 'undefined') { if (typeof currentUserEmail === "undefined") {
return; return;
} }
if (!currentUserEmail) { if (!currentUserEmail) {
@@ -26,13 +32,10 @@ const AppProvider = ({ children }) => {
return; return;
} }
return onSnapshot( return onSnapshot(
query( query(collection(db, "users"), where("email", "==", currentUserEmail)),
collection(db, "users"), (snapshot) => {
where("email", "==", currentUserEmail)
),
snapshot => {
const doc = snapshot.docs[0]; const doc = snapshot.docs[0];
if (typeof doc === 'undefined') { if (typeof doc === "undefined") {
appDispatch({ type: "DELETE_GROUP" }); appDispatch({ type: "DELETE_GROUP" });
} else { } else {
appDispatch({ type: "CREATE_GROUP", payload: doc.data() }); appDispatch({ type: "CREATE_GROUP", payload: doc.data() });

View File

@@ -8,6 +8,40 @@
margin: 30px 0px 0px 0px; margin: 30px 0px 0px 0px;
} }
.dash-promo-first-box {
margin-top: 8px;
padding: 8px 48px;
}
.user-name-span {
font-weight: 500;
}
.dash-promo-first-wrap {
padding: 8px 0px;
background-color: var(--barely-there-accent);
display: flex;
flex-direction: column;
border: 1px solid orange;
border-radius: 5px;
}
.dash-promo-first-textwrap {
display: flex;
flex-direction: column;
margin: auto;
}
.dash-promo-first-text {
font-size: 0.94rem;
letter-spacing: 0.03rem;
font-family: Roboto;
font-weight: 300;
margin-bottom: 2px;
margin-left: 16px;
width: 680px;
color: #3b3b3b;
}
.dash-heading-text { .dash-heading-text {
font-size: 1.3rem; font-size: 1.3rem;
} }
@@ -86,6 +120,11 @@
justify-content: flex-end; justify-content: flex-end;
flex-direction: row; flex-direction: row;
} }
@media only screen and (max-width: 860px) {
.dash-promo-first-text {
width: 500px;
}
}
@media only screen and (max-width: 430px) { @media only screen and (max-width: 430px) {
.dashboard-header { .dashboard-header {

View File

@@ -131,8 +131,8 @@ section.section-1 {
font-family: Roboto; font-family: Roboto;
color: #fff; color: #fff;
padding: 20px 0px 10px 0px; padding: 20px 0px 10px 0px;
font-size: 20px; font-size: 19px;
font-weight: 100; font-weight: 300;
max-width: 370px; max-width: 370px;
line-height: 29px; line-height: 29px;
text-align: justify; text-align: justify;
@@ -163,10 +163,10 @@ h1.heading-2 {
p.text-block-1 { p.text-block-1 {
color: #fff; color: #fff;
font-family: Roboto; font-family: Roboto;
font-size: 25px; font-size: 26px;
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
line-height: 1.6; line-height: 1.5;
width: 525px; width: 525px;
margin-top: 24px; margin-top: 24px;
} }
@@ -325,7 +325,7 @@ p.card-texts {
font-family: Roboto; font-family: Roboto;
font-size: 1.7rem; font-size: 1.7rem;
font-weight: 400; font-weight: 400;
margin-top: 8px; margin-top: 2px;
letter-spacing: -0.007rem; letter-spacing: -0.007rem;
color: #1f74a7; color: #1f74a7;
} }
@@ -362,7 +362,7 @@ p.card-title {
} }
.home-card-text-box { .home-card-text-box {
padding: 8px 10px 0px 10px; padding: 2px 10px 0px 10px;
width: 270px; width: 270px;
height: 150px; height: 150px;
} }

View File

@@ -57,6 +57,7 @@
flex-direction: row; flex-direction: row;
width: 167px; width: 167px;
margin-top: -2px; margin-top: -2px;
cursor: pointer;
} }
.novo-logo { .novo-logo {