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 { 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>

View File

@@ -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>
)

View File

@@ -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">

View File

@@ -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
);
};

View File

@@ -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>

View File

@@ -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>
) : (
<></>

View File

@@ -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() });

View File

@@ -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 {

View File

@@ -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;
}

View File

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