Skip to content

Commit

Permalink
finish the logic for free users. Need to add the logic for pro users.
Browse files Browse the repository at this point in the history
  • Loading branch information
dokmy committed Jan 11, 2024
1 parent 8a3fd32 commit 9f9c81f
Show file tree
Hide file tree
Showing 15 changed files with 346 additions and 44 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"react-dom": "18.2.0",
"react-icons": "^4.10.1",
"react-markdown": "^8.0.7",
"react-spinners": "^0.13.8",
"sswr": "^2.0.0",
"svelte": "^4.2.0",
"tailwind-merge": "^2.1.0",
Expand Down
17 changes: 17 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,20 @@ model Message {
@@index([searchResultId])
@@index([userId])
}

model UserSubscription {
id String @id @default(cuid())
userId String @unique
stripeCustomerId String? @unique @map(name: "stripe_customer_id")
stripeSubscriptionId String? @unique @map(name: "stripe_subscription_id")
stripePriceId String? @map(name: "stripe_price_id")
stripeCurrentPeriodEnd DateTime? @map(name: "stripe_current_period_end")
}

model UserSearchCredit {
id String @id @default(cuid())
userId String @unique
count Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
95 changes: 69 additions & 26 deletions src/app/(root)/(routes)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ import Link from "next/link";
import axios from "axios";
import { useState, useEffect } from "react";
import { Search } from "@prisma/client";
import { SearchResult } from "@prisma/client";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";

type SearchWithResults = Search & { searchResults: SearchResult[] };

const dashboardPage = () => {
const [searches, setSearches] = useState<null | Search[]>(null);
const [searches, setSearches] = useState<null | SearchWithResults[]>(null);
const { user } = useUser();
useEffect(() => {
const fetchSearches = async () => {
Expand All @@ -34,7 +38,16 @@ const dashboardPage = () => {
fetchSearches();
}, [user]);

const formatDate = (dateString) => {
const formatPrefixFilters = (filters: string) => {
if (filters == "[]") {
return "No Filters";
} else {
filters = filters.replace(/[\[\]']+/g, "");
return filters;
}
};

const formatDate = (dateString: string | null | Date) => {
// Check if dateString is not provided or is empty
if (!dateString) {
return "N/A";
Expand Down Expand Up @@ -65,37 +78,67 @@ const dashboardPage = () => {
}

return (
<div className="flex flex-row flex-wrap overflow-x-auto gap-4 p-5 justify-center">
<div className="flex flex-row flex-wrap overflow-x-auto gap-5 p-5 justify-center">
{searches.map((search, index) => (
<div key={index}>
<Card key={index} className="w-96 h-96">
<div key={index} className="w-96 space-3 h-full">
<Card className="w-full max-w-sm mx-auto bg-gray-800 text-white">
<CardHeader>
<CardTitle>{"Search " + (index + 1)}</CardTitle>
{/* <CardDescription>Card Description</CardDescription> */}
<CardDescription>Your Search Settings:</CardDescription>
</CardHeader>
<CardContent className="break-words">
<ul className="px-3">
<li>
<strong>Query:</strong> {search.query}
</li>
<li>
<strong>Filters:</strong>{" "}
{search.prefixFilters ? search.prefixFilters : "N/A"}
</li>
<li>
<strong>Search Period:</strong> {formatDate(search.minDate)} -{" "}
{formatDate(search.maxDate)}
</li>
<li>
<strong>Search Date:</strong> {formatDate(search.createdAt)}
</li>
</ul>
<CardContent className="grid gap-4">
<div className="grid gap-2">
<div className="grid gap-2 border-2 border-gray-600 bg-[#1c204f] p-2 rounded-md">
<Label htmlFor="query">Search Query</Label>
<p className="text-sm text-gray-100" id="query">
{search.query}
</p>
</div>
</div>

<div className="grid gap-2 border-2 border-gray-600 bg-gray-700 p-2 rounded-md">
<div className="grid gap-2">
<Label htmlFor="results">Search Results</Label>
<ul
className="list-disc list-inside text-sm text-gray-300"
id="results"
>
{search.searchResults.map((result, index) => (
<li key={index}>{result.caseActionNo}</li>
))}
</ul>
</div>
<div className="grid gap-2">
<Label htmlFor="count">Number of Search Results</Label>
<p className="text-sm text-gray-300" id="count">
{search.searchResults.length} results
</p>
</div>
<div className="grid gap-2">
<Label htmlFor="period">Search Period</Label>
<p className="text-sm text-gray-300" id="period">
{formatDate(search.minDate)} - {formatDate(search.maxDate)}
</p>
</div>
<div className="grid gap-2">
<Label htmlFor="date">Search Date</Label>
<p className="text-sm text-gray-300" id="date">
{formatDate(search.createdAt)}
</p>
</div>
<div className="grid gap-2">
<Label htmlFor="filters">Search Filters</Label>
<p className="text-sm text-gray-300" id="filters">
{formatPrefixFilters(search.prefixFilters)}
</p>
</div>
</div>
</CardContent>
<CardFooter>
<div className="flex justify-center p-4">
<Link href={`/results/${search.id}`}>
<Button className="w-full">Mark all as read</Button>
<Button>Chat with Results</Button>
</Link>
</CardFooter>
</div>
</Card>
</div>
))}
Expand Down
37 changes: 32 additions & 5 deletions src/app/(root)/(routes)/search/components/search-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SortBy from "@/components/sort-by";
import { Button } from "@mui/material";
import { performSearch } from "@/lib/performSearch";
import { useRouter } from "next/navigation";
import MoonLoader from "react-spinners/MoonLoader";

const SearchForm = () => {
const [searchQuery, setSearchQuery] = useState("");
Expand Down Expand Up @@ -105,6 +106,8 @@ const SearchForm = () => {
event.preventDefault();
console.log("here");

setIsLoading(true);

let hasError = false;

if (!searchQuery) {
Expand All @@ -131,14 +134,27 @@ const SearchForm = () => {
selectedMinDate,
selectedMaxDate,
sortOption,
}).then(({ apiResults, searchId }) => {
router.refresh();
router.push(`/results/${searchId}`);
});
})
.then(({ apiResults, searchId, noCredits }) => {
if (noCredits) {
alert("Not enough credits. Please upgrade or buy more.");
router.push(`/settings`);
} else {
router.refresh();
router.push(`/results/${searchId}`);
}
setIsLoading(false);
})
.catch((error) => {
console.error("Error during search:", error);
// Handle any errors that occurred during performSearch
setIsLoading(false);
});
}
};

const [searchQueryError, setSearchQueryError] = useState(false);
const [isLoading, setIsLoading] = useState(false);

return (
<div className="w-full px-52 py-5 flex-col">
Expand Down Expand Up @@ -180,6 +196,7 @@ const SearchForm = () => {
<Button
variant="contained"
size="large"
disabled={isLoading}
sx={{
bgcolor: "black",
borderColor: "grey",
Expand All @@ -189,7 +206,17 @@ const SearchForm = () => {
}}
type="submit"
>
Search
{isLoading ? (
<MoonLoader
color="#36d7b7"
loading={isLoading}
size={20} // Adjust size as needed
aria-label="Loading Spinner"
data-testid="loader"
/>
) : (
"Search"
)}
</Button>
</div>
</form>
Expand Down
12 changes: 10 additions & 2 deletions src/app/(root)/(routes)/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React from "react";
import SubscriptionButton from "@/components/subcription-button";
import { checkSubscription } from "@/lib/subscriptions";

const settingsPage = () => {
return <div>settingsPage</div>;
const settingsPage = async () => {
const hasSubscription = await checkSubscription();

return (
<div className="items-center">
<SubscriptionButton hasSubscription={hasSubscription} />
</div>
);
};

export default settingsPage;
4 changes: 3 additions & 1 deletion src/app/(root)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Navbar from "@/components/navbar";
import { Sidebar } from "@/components/sidebar";
import { checkSubscription } from "@/lib/subscriptions";

const RootLayout = async ({ children }: { children: React.ReactNode }) => {
const hasSubscription = await checkSubscription();
return (
<div className="flex flex-col h-screen">
<div className="fixed inset-y-0 w-full h-16 z-20">
<Navbar />
<Navbar hasSubscription={hasSubscription} />
</div>
<div className="hidden md:flex mt-16 h-full w-20 flex-col fixed inset-y-0 border-r">
<Sidebar />
Expand Down
6 changes: 5 additions & 1 deletion src/app/api/get-searches/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ export const POST = async (req: Request) => {
},
orderBy: {
createdAt: 'desc'
}
},

include: {
searchResults: true,
},
});

return NextResponse.json(_searches);
Expand Down
33 changes: 33 additions & 0 deletions src/app/api/search/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import dayjs from "dayjs";
import prismadb from '../../../lib/prismadb';
import { auth, currentUser } from "@clerk/nextjs";
import { NextResponse } from 'next/server';
import { checkSubscription } from '@/lib/subscriptions';
import { checkSearchCredits, deductSearchCredit, getSearchCreditCount, incrementSearchCredit } from '@/lib/searchCredits';




Expand Down Expand Up @@ -41,6 +44,36 @@ function convertToUrl(caseRef:string) {

export async function POST(req: Request) {


const {userId} = auth()

if (!userId) {
return new NextResponse("Unauthorized", {status: 401})
}

const inSearchCreditsDb = await checkSearchCredits()

if (!inSearchCreditsDb) {
incrementSearchCredit(5)
}

const creditsLeft = await getSearchCreditCount()

if (creditsLeft == 0) {
return new NextResponse("No more credits. Please upgrade or buy more credits." , {status:403})
}

if (creditsLeft == false) {
return new NextResponse("Not inside credits database", {status: 401})
}



if (creditsLeft > 0) {
deductSearchCredit()
}


try {
const { filters, searchQuery, selectedMinDate, selectedMaxDate, sortOption } = await req.json()

Expand Down
8 changes: 3 additions & 5 deletions src/app/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import FastLegalLogo from "../../../public/logo_rec.png";
import FastLegalLogoWhite from "../../../public/logo_white_rec.jpeg";
import { Menu } from "lucide-react";
import Link from "next/link";
import { Button } from "./ui/button";
import { ModeToggle } from "@/components/mode-toggle";
import { useTheme } from "next-themes";
import SubscriptionButton from "./subcription-button";

const Navbar = () => {
const Navbar = ({ hasSubscription = false }: { hasSubscription: boolean }) => {
const { theme } = useTheme();

const logo = theme === "light" ? FastLegalLogoWhite : FastLegalLogo;
Expand All @@ -30,8 +29,7 @@ const Navbar = () => {
</Link>

<div className="mr-3 flex flex-row items-center gap-x-3">
<Button className="destructive">Upgrade</Button>
{/* <ModeToggle /> */}
<SubscriptionButton hasSubscription={false} />
<UserButton afterSignOutUrl="/" />
</div>
</header>
Expand Down
Empty file removed src/app/components/search-card.tsx
Empty file.
26 changes: 26 additions & 0 deletions src/app/components/subcription-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { Button } from "./ui/button";
import Link from "next/link";

interface SubscriptionProps {
hasSubscription: boolean;
}

const SubscriptionButton: React.FC<SubscriptionProps> = ({
hasSubscription,
}) => {
if (hasSubscription) {
return (
<Link href="/">
<Button>Manage Subscription</Button>
</Link>
);
}
return (
<Link href="/">
<Button>Upgrade</Button>
</Link>
);
};

export default SubscriptionButton;
Loading

0 comments on commit 9f9c81f

Please sign in to comment.