@@ -1,5 +1,10 @@
|
||||
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 { useSearchParams } from "react-router-dom";
|
||||
|
||||
@@ -75,122 +80,133 @@ const PasswordResetPage = () => {
|
||||
} finally {
|
||||
setIsBusy(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const resetMode = mode === "resetPassword" ? "resetPassword" : "enterEmail";
|
||||
return (
|
||||
<div className="password-reset-container">
|
||||
<div className="password-reset-form-wrapper">
|
||||
<div className="password-reset-form">
|
||||
{resetMode === "enterEmail" ? <>
|
||||
<div className="password-reset-header">
|
||||
<h2 className="password-reset-header-text">
|
||||
Enter Account Email
|
||||
</h2>
|
||||
</div>
|
||||
{!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>
|
||||
{resetMode === "enterEmail" ? (
|
||||
<>
|
||||
<div className="password-reset-header">
|
||||
<h2 className="password-reset-header-text">
|
||||
Enter Account Email
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
</> : null}
|
||||
{resetMode === "resetPassword" ? <>
|
||||
<div className="password-reset-header">
|
||||
<h2 className="password-reset-header-text">
|
||||
Enter New Password
|
||||
</h2>
|
||||
</div>
|
||||
{!done && isCodeValid !== null && isCodeValid ? (
|
||||
<form>
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
type="password"
|
||||
className="form-control"
|
||||
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>
|
||||
{!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 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>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
{resetMode === "resetPassword" ? (
|
||||
<>
|
||||
<div className="password-reset-header">
|
||||
<h2 className="password-reset-header-text">
|
||||
Enter New Password
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
{done && (
|
||||
<div className="success-container">
|
||||
<p className="reset-sent-text">Password changed.</p>
|
||||
</div>
|
||||
)}
|
||||
</> : null}
|
||||
{!done && isCodeValid !== null && isCodeValid ? (
|
||||
<form>
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
type="password"
|
||||
className="form-control"
|
||||
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>
|
||||
|
||||
@@ -83,6 +83,7 @@ const CaseListPage = ({ perPage }) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const dropDownOptions = [
|
||||
{ label: "Case name a - z", value: "caption" },
|
||||
{ label: "Case name z - a", value: "caption2" },
|
||||
@@ -159,11 +160,17 @@ const CaseListPage = ({ perPage }) => {
|
||||
</>
|
||||
) : (
|
||||
<div className="nodocs-text-container">
|
||||
<p> You have not created any cases yet.</p>
|
||||
<p> Please create your first case.</p>
|
||||
<p>
|
||||
To get started, click "Create New Case" and enter case
|
||||
information.
|
||||
To create a discovery request or response, you will first enter
|
||||
some basic information about the case they will pertain to -
|
||||
i.e. the caption and case number.
|
||||
</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()}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -15,21 +15,26 @@ import { Typeahead } from "react-bootstrap-typeahead";
|
||||
import { AppContext } from "../../Hooks/useContext/appContext.js";
|
||||
import UploadModal from "../Modals/UploadModal.js";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import { getAuth } from "firebase/auth";
|
||||
|
||||
const Dashboard = () => {
|
||||
const size = window.innerWidth < 440;
|
||||
const [isMobile, setIsMobile] = useState(size);
|
||||
const auth = getAuth();
|
||||
const count = useRef(null);
|
||||
const navigate = useNavigate();
|
||||
const [allCases, setAllCases] = useState(null);
|
||||
const [selectedCase, setSelectedCase] = useState(null);
|
||||
const [showModal, setShowModal] = useState();
|
||||
const [docCount, setDocCount] = useState();
|
||||
const [isPromoFirstLogin, setIsPromoFirstLogin] = useState(true);
|
||||
const [responseCount, setResponseCount] = useState();
|
||||
const { appState } = useContext(AppContext);
|
||||
const { group } = appState;
|
||||
const appUserId = group ? group.appUserId : null;
|
||||
const isDashboard = true;
|
||||
console.log("group on dashbaord page", group);
|
||||
console.log("auth in dashoabrd page", auth);
|
||||
|
||||
useEffect(() => {
|
||||
if (count.current == null) {
|
||||
@@ -177,6 +182,31 @@ const Dashboard = () => {
|
||||
<div className="user-name-container2">{group.firm}</div>
|
||||
</div>
|
||||
<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-row-box">
|
||||
<div className="stats-unit-wrapper">
|
||||
|
||||
@@ -1,284 +1,478 @@
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { collection, setDoc, doc } from "firebase/firestore";
|
||||
import { db } from "../../firebase";
|
||||
import { db, auth } from "../../firebase";
|
||||
import Button from "../../pageElements/Button";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import arrow from "../../Assets/Images/Arrow.png";
|
||||
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 LoadingSpinner from "../../pageElements/LoadingSpinner";
|
||||
|
||||
const HomePage = () => {
|
||||
const navigate = useNavigate();
|
||||
const [showPromoModal, setShowPromoModal] = useState(false);
|
||||
const [isBusy, setIsBusy] = useState(false);
|
||||
const [notice, setNotice] = useState("");
|
||||
|
||||
const handleNavigate = () => {
|
||||
navigate("/signup");
|
||||
const apiUrl =
|
||||
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 = () => {
|
||||
navigate("/login");
|
||||
};
|
||||
|
||||
const handleCancelModal = () => {
|
||||
setShowPromoModal(!showPromoModal);
|
||||
navigate("/signup");
|
||||
};
|
||||
|
||||
const handleDemo = () => {
|
||||
const supReq = null;
|
||||
navigate("/requestpage/supReq");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="homepage-container">
|
||||
<section
|
||||
className="section-1"
|
||||
const homeContent = (
|
||||
<div className="homepage-container">
|
||||
<section
|
||||
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={{
|
||||
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",
|
||||
}}
|
||||
>
|
||||
<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={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 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>
|
||||
</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>
|
||||
</section>
|
||||
{showPromoModal ? (
|
||||
<ConfirmModal
|
||||
titleText="Enter Promo Code"
|
||||
onCancel={handleCancelModal}
|
||||
buttonLabelText="Enter Code"
|
||||
isPromoModal={true}
|
||||
onConfirm={handleProcessPromoSubscription}
|
||||
cancelButtonText="I don't have a code"
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</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 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>
|
||||
</>
|
||||
return isBusy ? (
|
||||
<LoadingSpinner message={""} loaderType="MoonLoader" />
|
||||
) : (
|
||||
homeContent
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ const ConfirmModal = ({
|
||||
isPromoModal,
|
||||
cancelButtonText,
|
||||
}) => {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const title = titleText ? titleText : "Confirmation";
|
||||
|
||||
return (
|
||||
@@ -53,11 +54,11 @@ const ConfirmModal = ({
|
||||
<TextInput
|
||||
key={"captionTwo"}
|
||||
name={"captionTwo"}
|
||||
value={issueText}
|
||||
value={inputValue}
|
||||
message={"data.captionTwo.message"}
|
||||
onChange={(e) => setIssueText(e.target.value)}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
label={
|
||||
issueText
|
||||
inputValue
|
||||
? ""
|
||||
: isPromoModal
|
||||
? "Enter your promotional code"
|
||||
@@ -79,7 +80,7 @@ const ConfirmModal = ({
|
||||
<Button
|
||||
disabled={isBusy}
|
||||
className="primary-button"
|
||||
onClick={onConfirm}
|
||||
onClick={() => onConfirm(inputValue)}
|
||||
labelText={buttonLabelText}
|
||||
/>
|
||||
</Modal.Footer>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState } from "react";
|
||||
import Col from "react-bootstrap/Col";
|
||||
import Form from "react-bootstrap/Form";
|
||||
import Row from "react-bootstrap/Row";
|
||||
@@ -75,9 +75,9 @@ const SignupPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmPromoCode = () => {
|
||||
if (issueText === marchEmailPrm) {
|
||||
handlePromoSignup();
|
||||
const handleConfirmPromoCode = (code) => {
|
||||
if (code === marchEmailPrm) {
|
||||
handlePromoSignup(code);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -467,7 +467,7 @@ const SignupPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePromoSignup = async () => {
|
||||
const handlePromoSignup = async (code) => {
|
||||
let dataValues = validateUserData();
|
||||
if (dataValues === null) {
|
||||
return;
|
||||
@@ -540,7 +540,8 @@ const SignupPage = () => {
|
||||
<h1 className="signup-header-text">Create A Novodraft Account</h1>
|
||||
{!isUpgrade ? (
|
||||
<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>
|
||||
) : (
|
||||
<></>
|
||||
|
||||
@@ -2,7 +2,13 @@ import React, { createContext, useContext, useEffect, useReducer } from "react";
|
||||
import { useGroupReducer } from "../useReducer/reducers";
|
||||
import { AuthContext } from "../../Context/AuthProvider";
|
||||
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 = {
|
||||
group: undefined,
|
||||
@@ -16,9 +22,9 @@ const AppContext = createContext({
|
||||
const AppProvider = ({ children }) => {
|
||||
const { currentUserEmail } = useContext(AuthContext);
|
||||
const [appState, appDispatch] = useReducer(useGroupReducer, initialState);
|
||||
|
||||
console.log("currentUserEmail in AppProvider", currentUserEmail);
|
||||
useEffect(() => {
|
||||
if (typeof currentUserEmail === 'undefined') {
|
||||
if (typeof currentUserEmail === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (!currentUserEmail) {
|
||||
@@ -26,13 +32,10 @@ const AppProvider = ({ children }) => {
|
||||
return;
|
||||
}
|
||||
return onSnapshot(
|
||||
query(
|
||||
collection(db, "users"),
|
||||
where("email", "==", currentUserEmail)
|
||||
),
|
||||
snapshot => {
|
||||
query(collection(db, "users"), where("email", "==", currentUserEmail)),
|
||||
(snapshot) => {
|
||||
const doc = snapshot.docs[0];
|
||||
if (typeof doc === 'undefined') {
|
||||
if (typeof doc === "undefined") {
|
||||
appDispatch({ type: "DELETE_GROUP" });
|
||||
} else {
|
||||
appDispatch({ type: "CREATE_GROUP", payload: doc.data() });
|
||||
|
||||
@@ -8,6 +8,40 @@
|
||||
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 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
@@ -86,6 +120,11 @@
|
||||
justify-content: flex-end;
|
||||
flex-direction: row;
|
||||
}
|
||||
@media only screen and (max-width: 860px) {
|
||||
.dash-promo-first-text {
|
||||
width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 430px) {
|
||||
.dashboard-header {
|
||||
|
||||
@@ -131,8 +131,8 @@ section.section-1 {
|
||||
font-family: Roboto;
|
||||
color: #fff;
|
||||
padding: 20px 0px 10px 0px;
|
||||
font-size: 20px;
|
||||
font-weight: 100;
|
||||
font-size: 19px;
|
||||
font-weight: 300;
|
||||
max-width: 370px;
|
||||
line-height: 29px;
|
||||
text-align: justify;
|
||||
@@ -163,10 +163,10 @@ h1.heading-2 {
|
||||
p.text-block-1 {
|
||||
color: #fff;
|
||||
font-family: Roboto;
|
||||
font-size: 25px;
|
||||
font-size: 26px;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
line-height: 1.6;
|
||||
line-height: 1.5;
|
||||
width: 525px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
@@ -325,7 +325,7 @@ p.card-texts {
|
||||
font-family: Roboto;
|
||||
font-size: 1.7rem;
|
||||
font-weight: 400;
|
||||
margin-top: 8px;
|
||||
margin-top: 2px;
|
||||
letter-spacing: -0.007rem;
|
||||
color: #1f74a7;
|
||||
}
|
||||
@@ -362,7 +362,7 @@ p.card-title {
|
||||
}
|
||||
|
||||
.home-card-text-box {
|
||||
padding: 8px 10px 0px 10px;
|
||||
padding: 2px 10px 0px 10px;
|
||||
width: 270px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
flex-direction: row;
|
||||
width: 167px;
|
||||
margin-top: -2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.novo-logo {
|
||||
|
||||
Reference in New Issue
Block a user