update pay function

This commit is contained in:
2025-11-22 11:42:43 +08:00
parent d8e4c737c5
commit 42b7d2ee63
176 changed files with 0 additions and 17400 deletions

View File

@@ -1,26 +0,0 @@
NEXT_PUBLIC_SUPABASE_URL=https://********************.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=****************************************************************************************************************************************************************************************************************
NEXT_PUBLIC_OPENAI_API_KEY=sk-************************************************
NEXT_PUBLIC_OPENAI_ASSISTANT_KEY=asst_************************
# Update these with your Supabase details from your project settings > API
SUPABASE_SERVICE_ROLE_KEY=***************************************************************************************************************************************************************************************************************************
# Update these with your Stripe credentials from https://dashboard.stripe.com/apikeys
# NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_***************************************************************************************************
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_***************************************************************************************************
# STRIPE_SECRET_KEY=sk_live_***************************************************************************************************
STRIPE_SECRET_KEY=sk_test_***************************************************************************************************
# The commented variable is usually for production webhook key. This you get in the Stripe dashboard and is usually shorter.
# STRIPE_WEBHOOK_SECRET=whsec_********************************
STRIPE_WEBHOOK_SECRET=whsec_****************************************************************
# Update this with your stable site URL only for the production environment.
# NEXT_PUBLIC_SITE_URL=https://horizon-ui.com/shadcn-nextjs-boilerplate
# NEXT_PUBLIC_SITE_URL=https://******************.com
NEXT_PUBLIC_AWS_S3_REGION=eu-north-1
NEXT_PUBLIC_AWS_S3_ACCESS_KEY_ID=********************
NEXT_PUBLIC_AWS_S3_SECRET_ACCESS_KEY=****************************************
NEXT_PUBLIC_AWS_S3_BUCKET_NAME=mybucket

View File

@@ -1,3 +0,0 @@
{
"extends": "next/core-web-vitals"
}

View File

@@ -1,47 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
.env.local.production
.env.local.new
.env.local.non-docker
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
yarn.lock
# editors
.vscode

View File

@@ -1,3 +0,0 @@
legacy-peer-deps=true
auto-install-peers=true
strict-peer-dependencies=false

View File

@@ -1,106 +0,0 @@
 
<p align="center">
<a href="https://horizon-ui.com/boilerplate" target="_blank">
<img src="https://i.ibb.co/LYGWM0W/top-boilerplate-readme.png" alt="Horizon UI Boilerplate - NextJS Template for Startups & Companies" width="400px" max-width="400px">
</a>
</p>
<p align="center">
<a style="color: #4318FF;" target="_blank" href="https://horizon-ui.com/boilerplate">Website</a>
<a style="color: #4318FF;" target="_blank" href="https://horizon-ui.com/docs-boilerplate/">Documentation</a>
<a style="color: #4318FF;" target="_blank" href="https://horizon-ui.com/pro">Admin Template</a>
<a style="color: #4318FF;" target="_blank" href="https://horizon-ui.com/ai-template">AI Template</a>
<a style="color: #4318FF;" target="_blank" href="https://twitter.com/horizon_ui">Twitter</a>
<p align="center" style="max-width: 500px; margin: auto;">
Launch your SaaS startup within a few days with the all-in-one NextJS boilerplate that you always searched for.
</p>
&nbsp;
<p align="center" style="width: 100%;">
<a style="display:flex; justify-content: center; width: 100%;" href="https://horizon-ui.com/boilerplate" target="_blank"><img style="border-radius: 10px; width: 100%;" src="https://i.ibb.co/G0xrhsk/horizon-boilerplate-image-readme.png" alt="Horizon UI Free Tailwind CSS Landing Page Kit" /></a>
</p>
&nbsp;
# Quickstart install
Install our product by running either of the following:
- Open the .zip archive file you got when you bought Horizon
&nbsp;
- Install NodeJS LTS from [NodeJs Official Page](https://nodejs.org/en/) (NOTE: Product only works with LTS version).
&nbsp;
Run in the terminal this command:
```
npm install
```
<br />
Then run this command to start your local server:
```
npm run dev
```
&nbsp;
# Documentation
View <a href="https://horizon-ui.com/docs-boilerplate/" target="_blank">full documentation here</a>
---
# Example Sections
If you want to get inspiration for your startup project or just show something directly to your clients, you can jump-start your development with our pre-built example sections. You will be able to quickly set up the basic structure for your web project.
View <a href="https://horizon-ui.com/boilerplate#pages" target="_blank">example sections here</a>
---
# Reporting Issues
We use GitHub Issues as the official bug tracker for the Horizon UI. Here are
some advice for our users who want to report an issue:
1. Make sure that you are using the latest version of the Horizon UI Boilerplate. Check the CHANGELOG for your dashboard on our [CHANGE LOG File](https://github.com/horizon-ui/boilerplate-issues/blob/main/CHANGELOG.md).
<br />
1. Providing us with reproducible steps for the issue will shorten the time it takes for it to be fixed.
<br />
3. Some issues may be browser-specific, so specifying in what browser you encountered the issue might help.
---
# Community
Connect with the community! Feel free to ask questions, report issues, and meet new people who already use Horizon UI!
💬 [Join the #HorizonUI Discord Community!](https://discord.gg/f6tEKFBd4m)
### Copyright and license
⭐️ [Copyright 2024 Horizon UI](https://www.horizon-ui.com/?ref=readme-horizon)
📄 [Horizon UI License](https://horizon-ui.notion.site/End-User-License-Agreement-8fb09441ea8c4c08b60c37996195a6d5)
---
# Credits
Special thanks to the open-source resources that helped us create this awesome boilerplate package, including:
- [NextJS Subscription Payments](https://github.com/vercel/nextjs-subscription-payments)
- [ChatBot UI by mckaywrigley](https://github.com/mckaywrigley/chatbot-ui)

View File

@@ -1,17 +0,0 @@
{
"folders": [
{
"name": "project-root",
"path": "./"
},
{
"name": "supabase-functions",
"path": "supabase/functions"
}
],
"settings": {
"files.exclude": {
"supabase/functions/": true
}
}
}

View File

@@ -1,43 +0,0 @@
import { ChatBody } from '@/types/types';
import { OpenAIStream } from '@/utils/streams/chatStream';
export const runtime = 'edge';
export async function GET(req: Request): Promise<Response> {
try {
const { inputMessage, model, apiKey } = (await req.json()) as ChatBody;
let apiKeyFinal;
if (apiKey) {
apiKeyFinal = apiKey;
} else {
apiKeyFinal = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
}
const stream = await OpenAIStream(inputMessage, model, apiKeyFinal);
return new Response(stream);
} catch (error) {
console.error(error);
return new Response('Error', { status: 500 });
}
}
export async function POST(req: Request): Promise<Response> {
try {
const { inputMessage, model, apiKey } = (await req.json()) as ChatBody;
let apiKeyFinal;
if (apiKey) {
apiKeyFinal = apiKey;
} else {
apiKeyFinal = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
}
const stream = await OpenAIStream(inputMessage, model, apiKeyFinal);
return new Response(stream);
} catch (error) {
console.error(error);
return new Response('Error', { status: 500 });
}
}

View File

@@ -1,29 +0,0 @@
import { EssayBody } from '@/types/types';
import { OpenAIStream } from '@/utils/streams/essayStream';
export const runtime = 'edge';
const handler = async (req: Request): Promise<Response> => {
try {
const {
topic,
words,
essayType,
model,
apiKey
} = (await req.json()) as EssayBody;
if (!apiKey) {
return new Response('API key not found', { status: 500 });
}
const stream = await OpenAIStream(topic, essayType, words, model, apiKey);
return new Response(stream);
} catch (error) {
console.error(error);
return new Response('Error', { status: 500 });
}
};
export default handler;

View File

@@ -1,43 +0,0 @@
import { PremiumEssayBody } from '@/types/types';
import { OpenAIStream } from '@/utils/streams/premiumEssayStream';
export const runtime = 'edge';
const handler = async (req: Request): Promise<Response> => {
try {
const {
words,
topic,
essayType,
tone,
citation,
level,
citations,
model,
apiKey
} = (await req.json()) as PremiumEssayBody;
if (!apiKey) {
return new Response('API key not found', { status: 500 });
}
const stream = await OpenAIStream(
words,
topic,
essayType,
tone,
citation,
level,
citations,
model,
apiKey
);
return new Response(stream);
} catch (error) {
console.error(error);
return new Response('Error', { status: 500 });
}
};
export default handler;

View File

@@ -1,81 +0,0 @@
import { stripe } from '@/utils/stripe/config';
import {
manageSubscriptionStatusChange,
upsertPriceRecord,
upsertProductRecord
} from '@/utils/supabase/admin';
import { headers } from 'next/headers';
import Stripe from 'stripe';
const relevantEvents = new Set([
'product.created',
'product.updated',
'price.created',
'price.updated',
'checkout.session.completed',
'customer.subscription.created',
'customer.subscription.updated',
'customer.subscription.deleted'
]);
export async function POST(req: Request) {
const body = await req.text();
const sig = headers().get('Stripe-Signature') as string;
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event: Stripe.Event;
try {
if (!sig || !webhookSecret) return;
event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
} catch (err) {
console.log(`❌ Error message: ${err.message}`);
return new Response(`Webhook Error: ${err.message}`, { status: 400 });
}
if (relevantEvents.has(event.type)) {
try {
switch (event.type) {
case 'product.created':
case 'product.updated':
await upsertProductRecord(event.data.object as Stripe.Product);
break;
case 'price.created':
case 'price.updated':
await upsertPriceRecord(event.data.object as Stripe.Price);
break;
case 'customer.subscription.created':
case 'customer.subscription.updated':
case 'customer.subscription.deleted':
const subscription = event.data.object as Stripe.Subscription;
await manageSubscriptionStatusChange(
subscription.id,
subscription.customer as string,
event.type === 'customer.subscription.created'
);
break;
case 'checkout.session.completed':
const checkoutSession = event.data.object as Stripe.Checkout.Session;
if (checkoutSession.mode === 'subscription') {
const subscriptionId = checkoutSession.subscription;
await manageSubscriptionStatusChange(
subscriptionId as string,
checkoutSession.customer as string,
true
);
}
break;
default:
throw new Error('Unhandled relevant event!');
}
} catch (error) {
console.log(error);
return new Response(
'Webhook handler failed. View your nextjs function logs.',
{
status: 400
}
);
}
}
return new Response(JSON.stringify({ received: true }));
}

View File

@@ -1,35 +0,0 @@
import { getErrorRedirect, getStatusRedirect } from '@/utils/helpers';
import { createClient } from '@/utils/supabase/server';
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
// The `/auth/callback` route is required for the server-side auth flow implemented
// by the `@supabase/ssr` package. It exchanges an auth code for the user's session.
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get('code');
if (code) {
const supabase = createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (error) {
return NextResponse.redirect(
getErrorRedirect(
`${requestUrl.origin}/dashboard/signin`,
error.name,
"Sorry, we weren't able to log you in. Please try again."
)
);
}
}
// URL to redirect to after sign in process completes
return NextResponse.redirect(
getStatusRedirect(
`${requestUrl.origin}/dashboard/main`,
'Success!',
'You are now signed in.'
)
);
}

View File

@@ -1,36 +0,0 @@
import { createClient } from '@/utils/supabase/server';
import { NextResponse } from 'next/server';
import { NextRequest } from 'next/server';
import { getErrorRedirect, getStatusRedirect } from '@/utils/helpers';
export async function GET(request: NextRequest) {
// The `/auth/callback` route is required for the server-side auth flow implemented
// by the `@supabase/ssr` package. It exchanges an auth code for the user's session.
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get('code');
if (code) {
const supabase = createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (error) {
return NextResponse.redirect(
getErrorRedirect(
`${requestUrl.origin}/signin/forgot_password`,
error.name,
"Sorry, we weren't able to log you in. Please try again."
)
);
}
}
// URL to redirect to after sign in process completes
return NextResponse.redirect(
getStatusRedirect(
`${requestUrl.origin}/signin/update_password`,
'You are now signed in.',
'Please enter a new password for your account.'
)
);
}

View File

@@ -1,35 +0,0 @@
import Assistant from '@/components/dashboard/ai-assistant';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function AiAssistant() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Assistant
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,36 +0,0 @@
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import Chat from '@/components/dashboard/ai-chat';
import { Providers } from '@/components/providers';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function AiChat() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Chat
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,35 +0,0 @@
import Generator from '@/components/dashboard/ai-generator';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function AiGenerator() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Generator
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,35 +0,0 @@
import { Providers } from '@/components/providers';
import Main from '@/components/dashboard/main';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function MainPage() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Main
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,14 +0,0 @@
import { getUser } from '@/utils/supabase/queries';
import { redirect } from 'next/navigation';
import { createClient } from '@/utils/supabase/server';
export default async function Dashboard() {
const supabase = createClient();
const [user] = await Promise.all([getUser(supabase)]);
if (!user) {
return redirect('/dashboard/signin');
} else {
redirect('/dashboard/main');
}
}

View File

@@ -1,42 +0,0 @@
import PremiumGenerator from '@/components/dashboard/premium-generator';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function PremiumGeneratorPage() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
if (!subscription) {
redirect('/dashboard/main');
}
return (
<Providers>
{subscription ? (
<PremiumGenerator
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
) : (
<p>NICE TRY BUDDY</p>
)}
</Providers>
);
}

View File

@@ -1,35 +0,0 @@
import Settings from '@/components/dashboard/settings';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function SettingsPage() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Settings
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,71 +0,0 @@
import DefaultAuth from '@/components/auth';
import AuthUI from '@/components/auth/AuthUI';
import { Providers } from '@/components/providers';
import {
getAuthTypes,
getDefaultSignInView,
getRedirectMethod,
getViewTypes
} from '@/utils/auth-helpers/settings';
import { createClient } from '@/utils/supabase/server';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import illustration from '/public/img/auth/auth.png';
export default async function SignIn({
params,
searchParams
}: {
params: { id: string };
searchParams: { disable_button: boolean };
}) {
const { allowOauth, allowEmail, allowPassword } = getAuthTypes();
const viewTypes = getViewTypes();
const redirectMethod = getRedirectMethod();
// Declare 'viewProp' and initialize with the default value
let viewProp: string;
// Assign url id to 'viewProp' if it's a valid string and ViewTypes includes it
if (typeof params.id === 'string' && viewTypes.includes(params.id)) {
viewProp = params.id;
} else {
const preferredSignInView =
cookies().get('preferredSignInView')?.value || null;
viewProp = getDefaultSignInView(preferredSignInView);
return redirect(`/dashboard/signin/${viewProp}`);
}
// Check if the user is already logged in and redirect to the account page if so
const supabase = createClient();
const {
data: { user }
} = await supabase.auth.getUser();
if (user && viewProp !== 'update_password') {
return redirect('/dashboard/main');
} else if (!user && viewProp === 'update_password') {
return redirect('/dashboard/signin');
}
return (
<Providers>
<DefaultAuth
viewProp={viewProp}
illustrationBackground={illustration.src}
>
<div>
<AuthUI
viewProp={viewProp}
user={user}
allowPassword={allowPassword}
allowEmail={allowEmail}
redirectMethod={redirectMethod}
disableButton={searchParams.disable_button}
allowOauth={allowOauth}
/>
</div>
</DefaultAuth>
</Providers>
);
}

View File

@@ -1,11 +0,0 @@
import { getDefaultSignInView } from '@/utils/auth-helpers/settings';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
export default function SignIn() {
const preferredSignInView =
cookies().get('preferredSignInView')?.value || null;
const defaultView = getDefaultSignInView(preferredSignInView);
return redirect(`/dashboard/signin/${defaultView}`);
}

View File

@@ -1,34 +0,0 @@
import Subscription from '@/components/dashboard/subscription';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function SubscriptionPage() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<Subscription
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,35 +0,0 @@
import UsersList from '@/components/dashboard/users-list';
import { Providers } from '@/components/providers';
import {
getProducts,
getSubscription,
getUser,
getUserDetails
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
import { redirect } from 'next/navigation';
export default async function UserList() {
const supabase = createClient();
const [user, userDetails, products, subscription] = await Promise.all([
getUser(supabase),
getUserDetails(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
if (!user) {
return redirect('/dashboard/signin');
}
return (
<Providers>
<UsersList
userDetails={userDetails}
user={user}
products={products}
subscription={subscription}
/>
</Providers>
);
}

View File

@@ -1,29 +0,0 @@
import { EssayBody } from '@/types/types';
import { OpenAIStream } from '@/utils/streams/essayStream';
export const runtime = 'edge';
const handler = async (req: Request): Promise<Response> => {
try {
const {
topic,
words,
essayType,
model,
apiKey
} = (await req.json()) as EssayBody;
if (!apiKey) {
return new Response('API key not found', { status: 500 });
}
const stream = await OpenAIStream(topic, essayType, words, model, apiKey);
return new Response(stream);
} catch (error) {
console.error(error);
return new Response('Error', { status: 500 });
}
};
export default handler;

View File

@@ -1,81 +0,0 @@
import SupabaseProvider from './supabase-provider';
import Script from 'next/script';
import { PropsWithChildren } from 'react';
import '@/styles/globals.css';
export const dynamic = 'force-dynamic';
export default function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}: PropsWithChildren) {
return (
<html lang="en">
<head>
<title>
Horizon UI Boilerplate - Launch your startup project 10X in a few
moments - The best NextJS Boilerplate (This is an example)
</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{/* <!-- Social tags --> */}
<meta
name="keywords"
content="Add here your main keywords and separate them with a comma"
/>
<meta name="description" content="Add here your website description" />
{/* <!-- Schema.org markup for Google+ --> */}
<meta itemProp="name" content="Add here your website name / title" />
<meta
itemProp="description"
content="Add here your website description"
/>
<meta
itemProp="image"
content="Add here the link for your website SEO image"
/>
{/* <!-- Twitter Card data --> */}
<meta name="twitter:card" content="product" />
<meta
name="twitter:title"
content="Add here your website name / title"
/>
<meta
name="twitter:description"
content="Add here your website description"
/>
<meta
name="twitter:image"
content="Add here the link for your website SEO image"
/>
{/* <!-- Open Graph data --> */}
<meta
property="og:title"
content="Add here your website name / title"
/>
<meta property="og:type" content="product" />
<meta property="og:url" content="https://your-website.com" />
<meta
property="og:image"
content="Add here the link for your website SEO image"
/>
<meta
property="og:description"
content="Add here your website description"
/>
<meta
property="og:site_name"
content="Add here your website name / title"
/>
<link rel="canonical" href="https://your-website.com" />
<link rel="icon" href="/favicon.ico" />
</head>
<body style={{ background: 'white' }}>
<SupabaseProvider>
{/* @ts-ignore */}
<main id="skip">{children}</main>
</SupabaseProvider>
</body>
</html>
);
}

View File

@@ -1,10 +0,0 @@
import Landing from '@/components/landing';
import { Providers } from '@/components/providers';
export default async function PricingPage() {
return (
<Providers>
<Landing />
</Providers>
);
}

View File

@@ -1,23 +0,0 @@
import Pricing from '@/components/pricing';
import { Providers } from '@/components/providers';
import {
getProducts,
getUser,
getSubscription
} from '@/utils/supabase/queries';
import { createClient } from '@/utils/supabase/server';
export default async function PricingPage() {
const supabase = createClient();
const [user, products, subscription] = await Promise.all([
getUser(supabase),
getProducts(supabase),
getSubscription(supabase)
]);
return (
<Providers>
<Pricing user={user} products={products} subscription={subscription} />
</Providers>
);
}

View File

@@ -1,50 +0,0 @@
'use client';
import type { Database } from '@/types_db';
import { createPagesBrowserClient } from '@supabase/auth-helpers-nextjs';
import type { SupabaseClient } from '@supabase/auth-helpers-nextjs';
import { useRouter } from 'next/navigation';
import { createContext, useContext, useEffect, useState } from 'react';
type SupabaseContext = {
supabase: SupabaseClient<Database>;
};
const Context = createContext<SupabaseContext | undefined>(undefined);
export default function SupabaseProvider({
children
}: {
children: React.ReactNode;
}) {
const [supabase] = useState(() => createPagesBrowserClient());
const router = useRouter();
useEffect(() => {
const {
data: { subscription }
} = supabase.auth.onAuthStateChange((event) => {
if (event === 'SIGNED_IN') router.refresh();
});
return () => {
subscription.unsubscribe();
};
}, [router, supabase]);
return (
<Context.Provider value={{ supabase }}>
<>{children}</>
</Context.Provider>
);
}
export const useSupabase = () => {
const context = useContext(Context);
if (context === undefined) {
throw new Error('useSupabase must be used inside SupabaseProvider');
}
return context;
};

View File

@@ -1,54 +0,0 @@
import { Database } from '@/types_db';
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { cache } from 'react';
export const createServerSupabaseClient = cache(() =>
createServerComponentClient<Database>({ cookies })
);
export async function getUserDetails() {
const supabase = createServerSupabaseClient();
try {
const { data: userDetails } = await supabase
.from('users')
.select('*')
.single();
return userDetails;
} catch (error) {
console.error('Error:', error);
return null;
}
}
export async function getSubscription() {
const supabase = createServerSupabaseClient();
try {
const { data: subscription } = await supabase
.from('subscriptions')
.select('*, prices(*, products(*))')
.in('status', ['trialing', 'active'])
.maybeSingle()
.throwOnError();
return subscription;
} catch (error) {
console.error('Error:', error);
return null;
}
}
export const getActiveProductsWithPrices = async () => {
const supabase = createServerSupabaseClient();
const { data, error } = await supabase
.from('products')
.select('*, prices(*)')
.eq('active', true)
.eq('prices.active', true)
.order('metadata->index')
.order('unit_amount', { foreignTable: 'prices' });
if (error) {
console.log(error.message);
}
return data ?? [];
};

View File

@@ -1,26 +0,0 @@
import { Flex, useColorModeValue } from '@chakra-ui/react';
import ReactMarkdown from 'react-markdown';
export default function MessageBox(props: { output: string }) {
const { output } = props;
const textColor = useColorModeValue('#120F43', 'white');
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
return (
<Flex
w="100%"
p="15px 20px"
border="1px solid"
color={textColor}
borderColor={borderColor}
borderRadius="10px"
minH="564px"
fontSize="md"
fontWeight="500"
mb="28px"
>
<ReactMarkdown className="font-medium">
{output ? output : 'Your generated response will appear here...'}
</ReactMarkdown>
</Flex>
);
}

View File

@@ -1,28 +0,0 @@
import Card from '@/components/card/Card';
import { useColorModeValue } from '@chakra-ui/system';
import ReactMarkdown from 'react-markdown';
export default function MessageBox(props: { output: string }) {
const { output } = props;
const bgColor = useColorModeValue('white', 'whiteAlpha.100');
const textColor = useColorModeValue('#120F43', 'white');
const borderWidth = useColorModeValue('1px', '0px');
return (
<Card
display={output ? 'flex' : 'none'}
p="22px"
maxH="max-content"
color={textColor}
bg={bgColor}
backdropBlur="xl"
borderWidth={borderWidth}
fontSize={{ base: 'sm', md: '16px' }}
lineHeight={{ base: '24px', md: '26px' }}
fontWeight={'500'}
>
<ReactMarkdown className="font-medium">
{output ? output : ''}
</ReactMarkdown>
</Card>
);
}

View File

@@ -1,100 +0,0 @@
'use client';
import { signInWithEmail } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import {
Box,
Button,
Flex,
FormLabel,
Input,
useColorModeValue,
Link
} from '@chakra-ui/react';
// Define prop type with allowPassword boolean
interface EmailSignInProps {
allowPassword: boolean;
redirectMethod: string;
disableButton?: boolean;
}
export default function EmailSignIn({
allowPassword,
redirectMethod
}: EmailSignInProps) {
const router = redirectMethod === 'client' ? useRouter() : null;
const [isSubmitting, setIsSubmitting] = useState(false);
const textColor = useColorModeValue('navy.700', 'white');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await handleRequest(e, signInWithEmail, router);
setIsSubmitting(false);
};
return (
<Box mb={8}>
<form onSubmit={(e) => handleSubmit(e)}>
<FormLabel
htmlFor="email"
display="flex"
ms="4px"
fontSize="sm"
fontWeight="500"
color={textColor}
mb="8px"
>
Email
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="email"
placeholder="name@example.com"
type="email"
name="email"
mb="24px"
fontWeight="500"
size="lg"
/>
<Button
fontSize="sm"
variant="brand"
fontWeight="500"
w="100%"
h="50"
mb="24px"
type="submit"
isLoading={isSubmitting}
>
Sign in
</Button>
</form>
{allowPassword && (
<Flex direction="column">
<Link
href="/dashboard/signin/password_signin"
color={textColor}
fontWeight="medium"
>
Sign in with email and password
</Link>
<Link
href="/dashboard/signin/signup"
color={textColor}
fontWeight="medium"
>
Don't have an account? Sign up
</Link>
</Flex>
)}
</Box>
);
}

View File

@@ -1,106 +0,0 @@
'use client';
import { requestPasswordUpdate } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import {
Box,
Button,
Flex,
FormLabel,
Input,
useColorModeValue,
Link
} from '@chakra-ui/react';
// Define prop type with allowEmail boolean
interface ForgotPasswordProps {
allowEmail: boolean;
redirectMethod: string;
disableButton?: boolean;
}
export default function ForgotPassword({
allowEmail,
redirectMethod
}: ForgotPasswordProps) {
const router = redirectMethod === 'client' ? useRouter() : null;
const textColor = useColorModeValue('navy.700', 'white');
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await handleRequest(e, requestPasswordUpdate, router);
setIsSubmitting(false);
};
return (
<Box mb={8}>
<form onSubmit={(e) => handleSubmit(e)}>
<FormLabel
htmlFor="email"
display="flex"
ms="4px"
fontSize="sm"
fontWeight="500"
color={textColor}
mb="8px"
>
Email
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="email"
placeholder="name@example.com"
type="email"
name="email"
mb="24px"
fontWeight="500"
size="lg"
/>
<Button
fontSize="sm"
variant="brand"
fontWeight="500"
w="100%"
h="50"
mb="24px"
type="submit"
isLoading={isSubmitting}
>
Sign in
</Button>
</form>
<Flex direction="column">
<Link
href="/dashboard/signin/password_signin"
color={textColor}
fontWeight="medium"
>
Sign in with email and password
</Link>
{allowEmail && (
<Link
href="/dashboard/signin/email_signin"
color={textColor}
fontWeight="medium"
>
Sign in via magic link
</Link>
)}
<Link
href="/dashboard/signin/signup"
color={textColor}
fontWeight="medium"
>
Don't have an account? Sign up
</Link>
</Flex>
</Box>
);
}

View File

@@ -1,77 +0,0 @@
'use client';
import { signInWithOAuth } from '@/utils/auth-helpers/client';
import { type Provider } from '@supabase/supabase-js';
import { FcGoogle } from "react-icons/fc";
import { useState } from 'react';
import { useColorModeValue } from '@chakra-ui/system';
import { Box, Button, Icon, Input } from '@chakra-ui/react';
import { IconType } from 'react-icons';
type OAuthProviders = {
name: Provider;
displayName: string;
icon: IconType;
};
export default function OauthSignIn() {
// Chakra color mode
const googleBg = useColorModeValue('secondaryGray.300', 'whiteAlpha.200');
const googleText = useColorModeValue('navy.700', 'white');
const googleHover = useColorModeValue(
{ bg: 'gray.200' },
{ bg: 'whiteAlpha.300' },
);
const googleActive = useColorModeValue(
{ bg: 'secondaryGray.300' },
{ bg: 'whiteAlpha.200' },
);
const oAuthProviders: OAuthProviders[] = [
{
name: 'google',
displayName: 'Google',
icon: FcGoogle
}
/* Add desired OAuth providers here */
];
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await signInWithOAuth(e);
setIsSubmitting(false);
};
return (
<Box mt="40px">
{oAuthProviders.map((provider) => (
<form
key={provider.name}
className="pb-2"
onSubmit={(e) => handleSubmit(e)}
>
<Input type="hidden" name="provider" value={provider.name} />
<Button
fontSize="sm"
me="0px"
py="15px"
h="50px"
w="100%"
borderRadius="16px"
bg={googleBg}
color={googleText}
fontWeight="500"
_hover={googleHover}
_active={googleActive}
_focus={googleActive}
type="submit"
>
<Icon as={ provider.icon} w="20px" h="20px" me="10px" />
{provider.displayName}
</Button>
</form>
))}
</Box>
);
}

View File

@@ -1,132 +0,0 @@
'use client';
import { signInWithPassword } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import {
Box,
Button,
Flex,
FormLabel,
Input,
Link,
useColorModeValue
} from '@chakra-ui/react';
// Define prop type with allowEmail boolean
interface PasswordSignInProps {
allowEmail: boolean;
redirectMethod: string;
}
export default function PasswordSignIn({
allowEmail,
redirectMethod
}: PasswordSignInProps) {
const router = redirectMethod === 'client' ? useRouter() : null;
const [isSubmitting, setIsSubmitting] = useState(false);
const textColor = useColorModeValue('navy.700', 'white');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await handleRequest(e, signInWithPassword, router);
setIsSubmitting(false);
};
return (
<Box mb="auto">
<Box mb="8px">
<form noValidate={true} onSubmit={(e) => handleSubmit(e)}>
<FormLabel
htmlFor="email"
display="flex"
ms="4px"
fontWeight="500"
color={textColor}
mb="8px"
>
Email
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="email"
placeholder="name@example.com"
type="email"
name="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
mb="24px"
fontWeight="500"
size="lg"
/>
<FormLabel
htmlFor="password"
display="flex"
ms="4px"
fontWeight="500"
color={textColor}
mb="8px"
>
Password
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="password"
placeholder="Password"
type="password"
name="password"
autoComplete="current-password"
mb="24px"
fontWeight="500"
size="lg"
/>
<Button
fontSize="sm"
variant="brand"
fontWeight="500"
w="100%"
h="50"
mb="24px"
type="submit"
isLoading={isSubmitting}
>
Sign in
</Button>
</form>
</Box>
<Flex direction="column">
<Link
href="/dashboard/signin/forgot_password"
color={textColor}
fontWeight="medium"
>
Forgot your password?
</Link>
{allowEmail && (
<Link
href="/dashboard/signin/email_signin"
color={textColor}
fontWeight="medium"
>
Sign in via magic link
</Link>
)}
<Link
href="/dashboard/signin/signup"
color={textColor}
fontWeight="medium"
>
Don't have an account? Sign up
</Link>
</Flex>
</Box>
);
}

View File

@@ -1,131 +0,0 @@
'use client';
import React from 'react';
import { signUp } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import {
Flex,
useColorModeValue,
Link,
FormLabel,
Box,
Input,
Button
} from '@chakra-ui/react';
// Define prop type with allowEmail boolean
interface SignUpProps {
allowEmail: boolean;
redirectMethod: string;
}
export default function SignUp({ allowEmail, redirectMethod }: SignUpProps) {
const router = redirectMethod === 'client' ? useRouter() : null;
const [isSubmitting, setIsSubmitting] = useState(false);
const textColor = useColorModeValue('navy.700', 'white');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await handleRequest(e, signUp, router);
setIsSubmitting(false);
};
return (
<Box mb="auto" mt="20px">
<Box mb="8px">
<form noValidate={true} onSubmit={(e) => handleSubmit(e)}>
<FormLabel
htmlFor="email"
display="flex"
ms="4px"
fontWeight="500"
color={textColor}
mb="8px"
>
Email
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="email"
placeholder="name@example.com"
type="email"
name="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
mb="24px"
fontWeight="500"
size="lg"
/>
<FormLabel
htmlFor="password"
display="flex"
ms="4px"
fontWeight="500"
color={textColor}
mb="8px"
>
Password
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
id="password"
placeholder="Password"
type="password"
name="password"
autoComplete="current-password"
mb="24px"
fontWeight="500"
size="lg"
/>
<Button
fontSize="sm"
variant="brand"
fontWeight="500"
w="100%"
h="50"
mb="24px"
type="submit"
isLoading={isSubmitting}
>
Sign in
</Button>
</form>
</Box>
<Flex direction="column">
<Link
href="/dashboard/signin/forgot_password"
color={textColor}
fontWeight="medium"
>
Forgot your password?
</Link>
<Link
href="/dashboard/signin/password_signin"
color={textColor}
fontWeight="medium"
>
Already have an account?
</Link>
{allowEmail && (
<Link
href="/dashboard/signin/email_signin"
color={textColor}
fontWeight="medium"
>
Sign in via magic link
</Link>
)}
</Flex>
</Box>
);
}

View File

@@ -1,100 +0,0 @@
'use client';
import { updatePassword } from '@/utils/auth-helpers/server';
import { handleRequest } from '@/utils/auth-helpers/client';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
import {
Box,
Button,
FormLabel,
Input,
useColorModeValue
} from '@chakra-ui/react';
interface UpdatePasswordProps {
redirectMethod: string;
}
export default function UpdatePassword({
redirectMethod
}: UpdatePasswordProps) {
const router = redirectMethod === 'client' ? useRouter() : null;
const [isSubmitting, setIsSubmitting] = useState(false);
const textColor = useColorModeValue('navy.700', 'white');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true); // Disable the button while the request is being handled
await handleRequest(e, updatePassword, router);
setIsSubmitting(false);
};
return (
<Box mb={8}>
<form onSubmit={(e) => handleSubmit(e)}>
<FormLabel
htmlFor="password"
display="flex"
ms="4px"
fontSize="sm"
fontWeight="500"
color={textColor}
mb="8px"
>
New Password
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
mb="24px"
fontWeight="500"
size="lg"
id="password"
placeholder="Password"
type="password"
name="password"
autoComplete="current-password"
/>
<FormLabel
htmlFor="password"
display="flex"
ms="4px"
fontSize="sm"
fontWeight="500"
color={textColor}
mb="8px"
>
Confirm New Password
</FormLabel>
<Input
isRequired={true}
variant="auth"
fontSize="sm"
ms={{ base: '0px', md: '0px' }}
mb="24px"
fontWeight="500"
size="lg"
id="passwordConfirm"
placeholder="Password"
type="password"
name="passwordConfirm"
autoComplete="current-password"
/>
<Button
fontSize="sm"
variant="brand"
fontWeight="500"
w="100%"
h="50"
mb="24px"
type="submit"
isLoading={isSubmitting}
>
Sign in
</Button>
</form>
</Box>
);
}

View File

@@ -1,81 +0,0 @@
'use client';
import PasswordSignIn from '@/components/auth-ui/PasswordSignIn';
import EmailSignIn from '@/components/auth-ui/EmailSignIn';
import OauthSignIn from '@/components/auth-ui/OauthSignIn';
import ForgotPassword from '@/components/auth-ui/ForgotPassword';
import UpdatePassword from '@/components/auth-ui/UpdatePassword';
import SignUp from '@/components/auth-ui/Signup';
import { Flex, Text } from '@chakra-ui/react';
import { HSeparator } from '../separator/Separator';
export default function AuthUI(props: any) {
return (
<Flex
direction={'column'}
my="auto"
mt={{ base: '30px', md: '70px', lg: 'auto' }}
maxW={{ md: 'full', lg: '420px' }}
>
<Text fontSize="32px" fontWeight={'bold'} color="gray.900">
{props.viewProp === 'signup'
? 'Sign Up'
: props.viewProp === 'forgot_password'
? 'Forgot Password'
: props.viewProp === 'update_password'
? 'Update Password'
: props.viewProp === 'email_signin'
? 'Email Sign In'
: 'Sign In'}
</Text>
<Text fontSize="16px" color="gray.t00">
{props.viewProp === 'signup'
? 'Enter your email and password to sign up!'
: props.viewProp === 'forgot_password'
? 'Enter your email to get a passoword reset link!'
: props.viewProp === 'update_password'
? 'Choose a new password for your account!'
: props.viewProp === 'email_signin'
? 'Enter your email to get a magic link!'
: 'Enter your email and password to sign in!'}
</Text>
{props.viewProp !== 'update_password' &&
props.viewProp !== 'signup' &&
props.allowOauth && (
<>
<OauthSignIn />
<HSeparator my="20px" />
</>
)}
{props.viewProp === 'password_signin' && (
<PasswordSignIn
allowEmail={props.allowEmail}
redirectMethod={props.redirectMethod}
/>
)}
{props.viewProp === 'email_signin' && (
<EmailSignIn
allowPassword={props.allowPassword}
redirectMethod={props.redirectMethod}
disableButton={props.disableButton}
/>
)}
{props.viewProp === 'forgot_password' && (
<ForgotPassword
allowEmail={props.allowEmail}
redirectMethod={props.redirectMethod}
disableButton={props.disableButton}
/>
)}
{props.viewProp === 'update_password' && (
<UpdatePassword redirectMethod={props.redirectMethod} />
)}
{props.viewProp === 'signup' && (
<SignUp
allowEmail={props.allowEmail}
redirectMethod={props.redirectMethod}
/>
)}
</Flex>
);
}

View File

@@ -1,79 +0,0 @@
'use client';
import Footer from '@/components/footer/FooterAuthDefault';
import NavLink from '@/components/link/NavLink';
import { Box, Flex, Icon, Link, Text } from '@chakra-ui/react';
import { PropsWithChildren } from 'react';
import { FaChevronLeft } from 'react-icons/fa';
interface DefaultAuthLayoutProps extends PropsWithChildren {
children: JSX.Element;
illustrationBackground: string;
viewProp: any;
}
export default function DefaultAuthLayout(props: DefaultAuthLayoutProps) {
const { children, illustrationBackground } = props;
return (
<Flex position="relative" h="max-content">
<Flex
minH="100vh"
w="100%"
maxW={{ base: '90%', md: '66%', lg: '1313px' }}
mx="auto"
pt={{ sm: '0px', md: '0px' }}
px={{ lg: '30px', xl: '0px' }}
ps={{ xl: '70px' }}
justifyContent="start"
direction="column"
>
<Link
href="/"
width={'fit-content'}
mt={10}
mb={{ base: '', md: '', lg: '120px', xl: '150px' }}
>
<Flex
align="center"
ps={{ base: '25px', lg: '0px' }}
pt={{ lg: '0px', xl: '0px' }}
w="fit-content"
>
<Icon
as={FaChevronLeft}
me="12px"
h="13px"
w="8px"
color="gray.500"
/>
<Text ms="0px" fontSize="sm" color="gray.500">
Back to the website
</Text>
</Flex>
</Link>
{children}
<Box
display={{ base: 'none', md: 'block' }}
h="100%"
minH="100vh"
w={{ lg: '50vw', '2xl': '44vw' }}
position="absolute"
right="0px"
>
<Link href="/">
<Flex
bg={`url(${illustrationBackground})`}
justify="center"
align="end"
w="100%"
h="100%"
bgSize="cover"
bgPosition="50%"
position="absolute"
/>
</Link>
</Box>
<Footer />
</Flex>
</Flex>
);
}

View File

@@ -1,11 +0,0 @@
'use client';
import { useStyleConfig, chakra, forwardRef } from '@chakra-ui/react';
import { CustomCardProps } from '@/theme/theme';
const CustomCard = forwardRef<CustomCardProps, 'div'>((props, ref) => {
const { size, variant, ...rest } = props;
const styles = useStyleConfig('Card', { size, variant });
return <chakra.div ref={ref} __css={styles} {...rest} />;
});
export default CustomCard;

View File

@@ -1,64 +0,0 @@
'use client';
import Card from '@/components/card/Card';
import {
Flex,
Stat,
StatLabel,
StatNumber,
useColorModeValue,
Text,
} from '@chakra-ui/react';
export default function Default(props: {
startContent?: JSX.Element;
endContent?: JSX.Element;
name: string;
growth?: string | number;
value: string | number;
}) {
const { startContent, endContent, name, growth, value } = props;
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = 'gray.500';
return (
<Card>
<Flex
my="auto"
h="100%"
align={{ base: 'center', xl: 'start' }}
justify={{ base: 'center', xl: 'center' }}
alignItems="center"
>
{startContent}
<Stat my="auto" ms={startContent ? '18px' : '0px'}>
<StatLabel
lineHeight="100%"
color={textColorSecondary}
fontSize="sm"
mb="4px"
>
{name}
</StatLabel>
<StatNumber color={textColor} fontWeight="700" fontSize="lg">
{value}
</StatNumber>
{growth ? (
<Flex align="center">
<Text color="green.500" fontSize="xs" fontWeight="700" me="5px">
{growth}
</Text>
<Text color="gray.500" fontSize="xs" fontWeight="400">
since last month
</Text>
</Flex>
) : null}
</Stat>
<Flex ms="auto" w="max-content">
{endContent}
</Flex>
</Flex>
</Card>
);
}

View File

@@ -1,71 +0,0 @@
'use client';
import NavLink from '../link/NavLink';
import Card from '@/components/card/Card';
import {
Box,
Button,
Flex,
useColorModeValue,
Text,
Icon,
} from '@chakra-ui/react';
import { MdEdit } from 'react-icons/md';
export default function Default(props: {
illustration: string | JSX.Element;
name: string;
description: string;
link: string;
edit?: string;
action?: any;
admin?: boolean;
}) {
const { illustration, name, description, link, edit, admin } = props;
const textColor = useColorModeValue('#120F43', 'white');
const gray = useColorModeValue('gray.500', 'white');
return (
<NavLink href={link}>
<Card h="100%" py="24px" px="24px">
<Flex
my="auto"
h="100%"
direction={'column'}
align={{ base: 'center', xl: 'start' }}
justify={{ base: 'center', xl: 'center' }}
>
<Flex align="start" w="100%" mb="30px">
<Text fontSize="34px" lineHeight={'120%'}>
{illustration}
</Text>
{admin ? (
<Flex ms="auto">
<NavLink href={edit ? edit : '/admin/edit-template'}>
<Button
w="24px"
h="24px"
_hover={{}}
_focus={{}}
_active={{}}
bg="none"
>
<Icon w="24px" h="24px" as={MdEdit} color={gray} />
</Button>
</NavLink>
</Flex>
) : null}
</Flex>
<Box>
<Text fontSize="lg" color={textColor} fontWeight="700" mb="8px">
{name}
</Text>
<Text fontSize="sm" color={gray} fontWeight="500">
{description}
</Text>
</Box>
</Flex>
</Card>
</NavLink>
);
}

View File

@@ -1,23 +0,0 @@
'use client';
import dynamic from 'next/dynamic';
// import Chart from 'react-apexcharts';
const Chart = dynamic(() => import('react-apexcharts'), {
ssr: false
});
const BarChart = (props) => {
const { chartData, chartOptions } = props;
return (
// @ts-ignore
<Chart
options={chartOptions}
type="bar"
width="100%"
height="100%"
series={chartData}
/>
);
};
export default BarChart;

View File

@@ -1,23 +0,0 @@
'use client';
import dynamic from 'next/dynamic';
// import Chart from 'react-apexcharts';
const Chart = dynamic(() => import('react-apexcharts'), {
ssr: false
});
const LineChart = (props) => {
const { chartData, chartOptions } = props;
return (
// @ts-ignore
<Chart
options={chartOptions}
type="line"
width="100%"
height="100%"
series={chartData}
/>
);
};
export default LineChart;

View File

@@ -1,457 +0,0 @@
'use client';
/*eslint-disable*/
import MessageBoxChat from '@/components/MessageBoxChat';
import DashboardLayout from '@/components/layout';
import Bg from '@/public/img/ai-chat/bg-image.png';
import { Database } from '@/types_db';
import {
Button,
Flex,
Icon,
Image,
Input,
Text,
useColorModeValue
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import endent from 'endent';
import { useState } from 'react';
import { MdAutoAwesome, MdEdit, MdPerson } from 'react-icons/md';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
export default function AiAssistant(props: Props) {
// *** If you use .env.local variable for your API key, method which we recommend, use the apiKey variable commented below
// Input States
const [inputMessage, setInputMessage] = useState<string>('');
const [submitMessage, setSubmitMessage] = useState<string>('');
// Loading state
const [loading, setLoading] = useState<boolean>(false);
const [assistant, setAssistant] = useState(Object);
const [thread, setThread] = useState(Object);
const [res_message, setResMessage] = useState(Object);
const gray = useColorModeValue('gray.500', 'white');
const brandColor = useColorModeValue('brand.500', 'white');
const gradientBg2 = useColorModeValue(
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)',
'linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.31) 100%)'
);
const textColor = useColorModeValue('#120F43', 'white');
const placeholderColor = useColorModeValue(
{ color: 'gray.500' },
{ color: 'whiteAlpha.600' }
);
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
const createPrompt = (inputMessage: string) => {
const data = (inputMessage: string) => {
return endent` do me this:
${inputMessage}
`;
};
if (inputMessage) {
return data(inputMessage);
}
};
const getAssistant = async () => {
const gptResponse = await fetch(
'https://api.openai.com/v1/assistants/' +
process.env.NEXT_PUBLIC_OPENAI_ASSISTANT_KEY,
{
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
}
}
);
const assistant = await gptResponse.json();
return assistant;
};
const createThread = async () => {
const gptResponse = await fetch('https://api.openai.com/v1/threads', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
}
});
const thread = await gptResponse.json();
return thread;
};
const createMessage = async (thread_id: string) => {
const prompt = createPrompt(inputMessage);
const gptResponse = await fetch(
'https://api.openai.com/v1/threads/' + thread_id + '/messages',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
},
body: JSON.stringify({
role: 'user',
// content: topic,
content: prompt
})
}
);
const message = await gptResponse.json();
return message;
};
const getMessage = async (thread_id: string, message_id: string) => {
// https://api.openai.com/v1/threads/{thread_id}/messages/{message_id}
const gptResponse = await fetch(
'https://api.openai.com/v1/threads/' + thread_id + '/messages',
{
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
}
}
);
const message = await gptResponse.json();
console.log('I get the message.');
console.log(message);
return message;
};
const runAssistant = async (thread_id: string, assistant_id: string) => {
const gptResponse = await fetch(
'https://api.openai.com/v1/threads/' + thread_id + '/runs',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
},
body: JSON.stringify({
assistant_id: assistant_id
})
}
);
const run_res = await gptResponse.json();
return run_res;
};
const getRunAssistant = async (run_id: string, thread_id: string) => {
const gptResponse = await fetch(
'https://api.openai.com/v1/threads/' + thread_id + '/runs/' + run_id,
{
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
}
}
);
const run_res = await gptResponse.json();
console.log('I get the status.');
console.log(run_res);
return run_res;
};
const deleteThread = async (thread_id: string) => {
if (thread === undefined) {
return;
}
const gptResponse = await fetch(
'https://api.openai.com/v1/threads/' + thread_id,
{
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
'Content-Type': 'application/json',
'OpenAI-Beta': 'assistants=v1'
}
}
);
const thread_res = await gptResponse.json();
console.log(thread_res);
return thread_res;
};
const handleSubmit = async (e: any) => {
e.preventDefault();
setLoading(true);
// save the keys in storage browser
// @ts-ignore
localStorage.setItem('open_ai_key', process.env.NEXT_PUBLIC_OPENAI_API_KEY);
localStorage.setItem(
'assistant_key',
// @ts-ignore
process.env.NEXT_PUBLIC_OPENAI_ASSISTANT_KEY
);
const assistant_res = await getAssistant();
setAssistant(assistant_res);
const thread_res = await createThread();
setThread(thread_res);
const message = await createMessage(thread_res.id);
let runAssistantResponse = await runAssistant(
thread_res.id,
assistant_res.id
);
console.log(runAssistantResponse);
while (runAssistantResponse.status !== 'completed') {
runAssistantResponse = await getRunAssistant(
runAssistantResponse.id,
thread_res.id
);
if (runAssistantResponse.status === 'completed') {
console.log('Message is : ');
const call_response = await getMessage(thread_res.id, message.id);
setResMessage(call_response);
console.log(await deleteThread(thread_res.id));
} else {
// sleep for 2 second
await new Promise((r) => setTimeout(r, 2000));
}
}
console.log(assistant);
console.log(thread);
console.log(message);
console.log(runAssistantResponse);
setSubmitMessage(inputMessage);
setLoading(false);
};
// -------------- Copy Response --------------
// const copyToClipboard = (text: string) => {
// const el = document.createElement('textarea');
// el.value = text;
// document.body.appendChild(el);
// el.select();
// document.execCommand('copy');
// document.body.removeChild(el);
// };
const handleChange = (Event: any) => {
setInputMessage(Event.target.value);
};
return (
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="AI Generator"
description="AI Generator"
>
<Flex
position="relative"
w="100%"
direction="column"
pt={{ base: '20px', md: 0 }}
>
<Image
width={{ base: '340px', xl: '350px' }}
src={Bg.src}
position="absolute"
left={{ base: '-20%', md: '35%', lg: '38%' }}
top={{ base: '50%' }}
zIndex="0"
w="200px"
transform="translate(0, -50%)"
alt=" "
/>
<Flex
direction={'column'}
mx="auto"
minH={{ base: '75vh', xl: '85vh' }}
w="full"
maxW="1000px"
>
{/* Model Change */}
<Flex
w="100%"
direction={'column'}
mb={
res_message?.data?.[0]?.content?.[0].text?.value ? '20px' : 'auto'
}
>
<Text
textAlign={'center'}
fontSize="sm"
fontWeight={'500'}
color="secondaryGray.500"
>
Please make sure that you have set the environmental variable for
the Assistant Key.
</Text>
</Flex>
{/* Main Box */}
<Flex
mx="auto"
w="100%"
direction={'column'}
display={
res_message?.data?.[0]?.content?.[0].text?.value ? 'flex' : 'none'
}
mb="auto"
>
<Flex
mb="10px"
display={'flex'}
w="100%"
alignItems={'center'}
justifyContent="center"
>
<Flex
me="20px"
h="40px"
minH="40px"
minW="40px"
align="center"
borderRadius="full"
border="1px solid"
borderColor={borderColor}
>
<Icon as={MdPerson} color={brandColor} h="20px" w="20px" />
</Flex>
<Flex
zIndex={2}
borderRadius="14px"
w="100%"
border="1px solid"
borderColor={borderColor}
p="20px"
backdropFilter="blur(24px)"
>
<Text
color={textColor}
fontSize={{ base: 'sm', md: '16px' }}
fontWeight={'600'}
>
{submitMessage}
</Text>
<Icon
as={MdEdit}
color={'gray.500'}
h="20px"
w="20px"
ms="auto"
cursor={'pointer'}
/>
</Flex>
</Flex>
<Flex w="100%">
<Flex
me="20px"
h="40px"
minW="40px"
align="center"
justify={'center'}
borderRadius="full"
background={gradientBg2}
>
<Icon as={MdAutoAwesome} color={'white'} h="20px" w="20px" />
</Flex>
<MessageBoxChat
output={res_message?.data?.[0]?.content?.[0].text?.value}
/>
</Flex>
</Flex>
{/* Chat Input */}
<Flex mt="20px" justifyContent={'flex-center'} mx="auto">
<Input
color={textColor}
border="1px solid"
borderRadius={'45px'}
borderColor={borderColor}
w={{ md: '100%', xl: '45vw' }}
h="60px"
id="email"
fontSize={'sm'}
fontWeight="500"
placeholder="Type your message here..."
_placeholder={placeholderColor}
_focus={{ borderColor: 'none' }}
mb={{ base: '14px', md: '16px' }}
me="20px"
onChange={handleChange}
/>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
h="54px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg: 'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
minW="150px"
onClick={handleSubmit}
isLoading={loading}
>
Submit
</Button>
</Flex>
<Flex
mt="10px"
direction={{ base: 'column', md: 'row' }}
justifyContent="center"
alignItems={'center'}
>
<Text color={gray} textAlign="center" fontSize="xs">
Free Research Preview. ChatGPT may produce inaccurate information
about people, places, or facts. Consider checking important
information.
</Text>
</Flex>
</Flex>
</Flex>
</DashboardLayout>
);
}

View File

@@ -1,439 +0,0 @@
'use client';
/*eslint-disable*/
import MessageBoxChat from '@/components/MessageBoxChat';
import DashboardLayout from '@/components/layout';
import Bg from '@/public/img/ai-chat/bg-image.png';
import { ChatBody } from '@/types/types';
import { Database } from '@/types_db';
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
useColorModeValue,
Box,
Icon,
Flex,
Text,
Input,
Button,
Image
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { useState } from 'react';
import { MdAutoAwesome, MdBolt, MdEdit, MdPerson } from 'react-icons/md';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
export default function AiChat(props: Props) {
// *** If you use .env.local variable for your API key, method which we recommend, use the apiKey variable commented below
// Input States
const [inputOnSubmit, setInputOnSubmit] = useState<string>('');
const [inputMessage, setInputMessage] = useState<string>('');
// Response message
const [outputCode, setOutputCode] = useState<string>('');
// ChatGPT model
const [model, setModel] = useState('gpt-3.5-turbo');
// Loading state
const [loading, setLoading] = useState<boolean>(false);
const gray = useColorModeValue('gray.500', 'white');
const brandColor = useColorModeValue('brand.500', 'white');
const opacityBg = useColorModeValue('white', 'whiteAlpha.100');
const gradientBg = useColorModeValue(
'linear-gradient(180deg, #FBFBFF 0%, #CACAFF 100%)',
'linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.31) 100%)'
);
const gradientBg2 = useColorModeValue(
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)',
'linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.31) 100%)'
);
const shadow = useColorModeValue(
'14px 27px 45px rgba(112, 144, 176, 0.2)',
'unset'
);
const textColor = useColorModeValue('#120F43', 'white');
const placeholderColor = useColorModeValue(
{ color: 'gray.500' },
{ color: 'whiteAlpha.600' }
);
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
// API Key
const handleTranslate = async () => {
const apiKey = localStorage.getItem('apiKey');
setInputOnSubmit(inputMessage);
// Chat post conditions(maximum number of characters, valid message etc.)
const maxCodeLength = model === 'gpt-3.5-turbo' ? 700 : 700;
if (!apiKey?.includes('sk-')) {
alert('Please enter an API key.');
return;
}
if (!inputMessage) {
alert('Please enter your subject.');
return;
}
if (inputMessage.length > maxCodeLength) {
alert(
`Please enter code less than ${maxCodeLength} characters. You are currently at ${inputMessage.length} characters.`
);
return;
}
setOutputCode(' ');
setLoading(true);
const controller = new AbortController();
const body: ChatBody = {
inputMessage,
model,
apiKey
};
// -------------- Fetch --------------
const response = await fetch('/api/chatAPI', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
signal: controller.signal,
body: JSON.stringify(body)
});
if (!response.ok) {
setLoading(false);
if (response) {
alert(
'Something went wrong went fetching from the API. Make sure to use a valid API key.'
);
}
return;
}
const data = response.body;
if (!data) {
setLoading(false);
alert('Something went wrong');
return;
}
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
while (!done) {
setLoading(true);
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
setOutputCode((prevCode) => prevCode + chunkValue);
}
setLoading(false);
};
// -------------- Copy Response --------------
// const copyToClipboard = (text: string) => {
// const el = document.createElement('textarea');
// el.value = text;
// document.body.appendChild(el);
// el.select();
// document.execCommand('copy');
// document.body.removeChild(el);
// };
const handleChange = (Event: any) => {
setInputMessage(Event.target.value);
};
return (
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Essay Generator"
description="Essay Generator"
>
<Flex
w="100%"
direction={'column'}
pt={{ base: 5, md: 0 }}
position="relative"
>
<Image
width={{ base: '340px', xl: '350px' }}
src={Bg.src}
position="absolute"
left={{ base: '-20%', md: '35%', lg: '38%' }}
top={{ base: '50%' }}
zIndex="0"
w="200px"
transform="translate(0, -50%)"
alt=" "
/>
<Flex
mx="auto"
w="100%"
maxW="100%"
direction="column"
minH={{ base: '75vh', xl: '85vh' }}
>
{/* Model Change */}
<Flex w="100%" direction={'column'} mb={outputCode ? '20px' : 'auto'}>
<Flex
mx="auto"
mb="20px"
w="max-content"
borderRadius="60px"
zIndex={2}
>
<Flex
cursor={'pointer'}
justifyContent="center"
borderRadius="8px"
align={'center'}
py="16px"
transitionDuration={'0.3s'}
h="70px"
w="174px"
bg={model === 'gpt-3.5-turbo' ? opacityBg : 'transparent'}
boxShadow={model === 'gpt-3.5-turbo' ? shadow : 'unset'}
color={textColor}
fontWeight="700"
fontSize="18px"
onClick={() => setModel('gpt-3.5-turbo')}
>
<Flex
me="10px"
w="39px"
h="39px"
justify={'center'}
alignItems="center"
borderRadius="full"
bg={gradientBg}
>
<Icon
as={MdAutoAwesome}
color={brandColor}
h="20px"
w="20px"
/>
</Flex>
GPT-3.5
</Flex>
<Flex
cursor={'pointer'}
justifyContent="center"
borderRadius="8px"
align={'center'}
py="16px"
transitionDuration={'0.3s'}
h="70px"
w="174px"
bg={model === 'gpt-4-1106-preview' ? opacityBg : 'transparent'}
boxShadow={model === 'gpt-4-1106-preview' ? shadow : 'unset'}
color={textColor}
fontWeight="700"
fontSize="18px"
onClick={() => setModel('gpt-4-1106-preview')}
>
<Flex
me="10px"
w="39px"
h="39px"
justify={'center'}
alignItems="center"
borderRadius="full"
bg={gradientBg}
>
<Icon as={MdBolt} color={brandColor} h="20px" w="20px" />
</Flex>
GPT-4
</Flex>
</Flex>
<Accordion zIndex={10} mx="auto" my="0px" color={gray} allowToggle>
<AccordionItem border="none">
<AccordionButton
borderBottom="0px solid"
maxW="max-content"
mx="auto"
_hover={{ border: '0px solid', bg: 'none' }}
_focus={{ border: '0px solid', bg: 'none' }}
>
<Box textAlign={'center'}>
<Text
fontSize="sm"
fontWeight={'500'}
color="secondaryGray.500"
>
No plugins added
</Text>
</Box>
<AccordionIcon color="secondaryGray.500" />
</AccordionButton>
<AccordionPanel mx="auto" w="max-content" p="0px 0px 10px 0px">
<Text
fontSize="sm"
fontWeight={'500'}
color="secondaryGray.500"
textAlign={'center'}
>
This is a cool text example.
</Text>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Flex>
{/* Main Box */}
<Flex
mx="auto"
w="100%"
direction={'column'}
display={outputCode ? 'flex' : 'none'}
mb="auto"
>
<Flex
mb="10px"
display={'flex'}
w="100%"
alignItems={'center'}
justifyContent="center"
>
<Flex
me="20px"
h="40px"
minH="40px"
minW="40px"
align="center"
justify={'center'}
borderRadius="full"
border="1px solid"
borderColor={borderColor}
>
<Icon as={MdPerson} color={brandColor} h="20px" w="20px" />
</Flex>
<Flex
zIndex={2}
borderRadius="14px"
w="100%"
border="1px solid"
borderColor={borderColor}
p="20px"
backdropFilter="blur(24px)"
>
<Text
color={textColor}
fontSize={{ base: 'sm', md: '16px' }}
fontWeight={'600'}
>
{inputOnSubmit}
</Text>
<Icon
as={MdEdit}
color={'gray.500'}
h="20px"
w="20px"
ms="auto"
cursor={'pointer'}
/>
</Flex>
</Flex>
<Flex w="100%">
<Flex
me="20px"
h="40px"
minW="40px"
align="center"
justify={'center'}
borderRadius="full"
background={gradientBg2}
>
<Icon as={MdAutoAwesome} color={'white'} h="20px" w="20px" />
</Flex>
<MessageBoxChat output={outputCode} />
</Flex>
</Flex>
{/* Chat Input */}
<Flex mt="20px" justifyContent={'flex-center'} mx="auto">
<Input
color={textColor}
border="1px solid"
borderRadius={'45px'}
borderColor={borderColor}
w={{ md: '100%', xl: '45vw' }}
h="60px"
id="email"
fontSize={'sm'}
fontWeight="500"
placeholder="Type your message here..."
_placeholder={placeholderColor}
_focus={{ borderColor: 'none' }}
mb={{ base: '14px', md: '16px' }}
me="20px"
onChange={handleChange}
/>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
h="54px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg: 'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
minW="150px"
onClick={handleTranslate}
isLoading={loading}
>
Submit
</Button>
</Flex>
<Flex
mt="10px"
direction={{ base: 'column', md: 'row' }}
justifyContent="center"
alignItems={'center'}
>
<Text color={gray} textAlign="center" fontSize="xs">
Free Research Preview. ChatGPT may produce inaccurate information
about people, places, or facts. Consider checking important
information.
</Text>
</Flex>
</Flex>
</Flex>
</DashboardLayout>
);
}

View File

@@ -1,912 +0,0 @@
/*eslint-disable*/
'use client';
import MessageBox from '@/components/MessageBox';
import Card from '@/components/card/Card';
import DashboardLayout from '@/components/layout';
import modalImage from '@/public/Modal.png';
import { EssayBody, OpenAIModel } from '@/types/types';
import { Database } from '@/types_db';
import { getErrorRedirect } from '@/utils/helpers';
import { getStripe } from '@/utils/stripe/client';
import {
Badge,
Button,
Flex,
FormLabel,
Icon,
Image,
Link,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
Select,
Text,
Textarea,
useColorModeValue,
useDisclosure,
useToast
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { usePathname, useRouter } from 'next/navigation';
import { useState } from 'react';
import { IoIosStar } from 'react-icons/io';
import {
MdCheckCircle,
MdChevronRight,
MdOutlineWorkspacePremium
} from 'react-icons/md';
import { checkoutWithStripe } from '@/utils/stripe/server';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
export default function AiGenerator(props: Props) {
const [priceIdLoading, setPriceIdLoading] = useState<string>();
const [plan, setPlan] = useState({
product: 'prod_PtTCPDFZbburMa',
price: 'price_1P3gGXGx8VbJPRgzdEZODy8K'
});
const router = useRouter();
const currentPath = usePathname();
const handleCheckout = async (price: Price) => {
setPriceIdLoading(price.id);
if (!props.user) {
setPriceIdLoading(undefined);
return router.push('/signin/signup');
}
const { errorRedirect, sessionId } = await checkoutWithStripe(
price,
currentPath
);
if (errorRedirect) {
setPriceIdLoading(undefined);
return router.push(errorRedirect);
}
if (!sessionId) {
setPriceIdLoading(undefined);
return router.push(
getErrorRedirect(
currentPath,
'An unknown error occurred.',
'Please try again later or contact a system administrator.'
)
);
}
const stripe = await getStripe();
stripe?.redirectToCheckout({ sessionId });
setPriceIdLoading(undefined);
};
// Input States
const { isOpen, onOpen, onClose } = useDisclosure();
const [words, setWords] = useState<'300' | '200'>('200');
const [essayType, setEssayType] = useState<
'' | 'Argumentative' | 'Classic' | 'Persuasive' | 'Critique'
>('');
const [topic, setTopic] = useState<string>('');
// Response message
const [outputCode, setOutputCode] = useState<string>('');
// ChatGPT model
const [model, setModel] = useState<OpenAIModel>('gpt-3.5-turbo');
// Loading state
const [loading, setLoading] = useState<boolean>(false);
// API Key
// const [apiKey, setApiKey] = useState<string>();
const textColor = useColorModeValue('#120F43', 'white');
const placeholderColor = useColorModeValue(
{ color: 'gray.500' },
{ color: 'whiteAlpha.600' }
);
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
const toast = useToast();
// -------------- Main API Handler --------------
const handleTranslate = async () => {
const maxCodeLength = model === 'gpt-3.5-turbo' ? 700 : 700;
// Chat post conditions(maximum number of characters, valid message etc.)
// if (!apiKey?.includes('sk-') && !apiKey?.includes('sk-')) {
// alert('Please enter an API key.');
// return;
// }
if (!topic) {
alert('Please enter your subject.');
return;
}
if (!words) {
alert('Please choose number of words.');
return;
}
if (!essayType) {
alert('Please choose a type of essay.');
return;
}
if (topic.length > maxCodeLength) {
alert(
`Please enter code less than ${maxCodeLength} characters. You are currently at ${topic.length} characters.`
);
return;
}
setLoading(true);
setOutputCode('');
const controller = new AbortController();
const body: EssayBody = {
topic,
words,
essayType,
model
};
// -------------- Fetch --------------
const response = await fetch('/api/essayAPI', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
signal: controller.signal,
body: JSON.stringify(body)
});
if (!response.ok) {
setLoading(false);
if (response) {
alert(
'Something went wrong went fetching from the API. Make sure to use a valid API key.'
);
}
return;
}
const data = response.body;
if (!data) {
setLoading(false);
alert('Something went wrong');
return;
}
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
let code = '';
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
code += chunkValue;
setOutputCode((prevCode) => prevCode + chunkValue);
}
setLoading(false);
copyToClipboard(code);
};
// -------------- Copy Response --------------
const copyToClipboard = (text: string) => {
const el = document.createElement('textarea');
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
// *** Initializing apiKey with .env.local value
// useEffect(() => {
// ENV file verison
// const apiKeyENV = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
// if (apiKey === undefined || null) {
// setApiKey(apiKeyENV);
// }
// }, []);
// -------------- Input Value Handler --------------
const handleChange = (Event: any) => {
setTopic(Event.target.value);
};
const handleChangeParagraphs = (Event: any) => {
setWords(Event.target.value);
};
const handleChangeEssayType = (Event: any) => {
setEssayType(Event.target.value);
};
return (
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Essay Generator"
description="Essay Generator"
>
<Flex
w="100%"
direction="column"
position="relative"
mt={{ base: '70px', md: '0px', xl: '0px' }}
>
<Flex
mx="auto"
w={{ base: '100%', md: '100%', xl: '100%' }}
maxW="100%"
justify="center"
direction={{ base: 'column', md: 'row' }}
>
<Card
minW={{ base: '100%', md: '40%', xl: '476px' }}
maxW={{ base: '100%', md: '40%', xl: '476px' }}
h="min-content"
me={{ base: '0px', md: '20px' }}
mb={{ base: '20px', md: '0px' }}
>
<Text
fontSize={'30px'}
color={textColor}
fontWeight="800"
mb="10px"
>
Essay Topic
</Text>
<Text fontSize="md" color="gray.500" fontWeight="500" mb="30px">
What your essay will be about?
</Text>
<Textarea
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
p="15px 20px"
mb="28px"
minH="224px"
fontWeight="500"
_focus={{ borderColor: 'none' }}
color={textColor}
placeholder="Type here your topic..."
_placeholder={placeholderColor}
onChange={handleChange}
/>
<FormLabel
display="flex"
ms="10px"
htmlFor={'parag'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Number of words
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="type"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeParagraphs}
>
<option value={'200'}>200</option>
<option value={'300'}>300</option>
</Select>
<FormLabel
display="flex"
ms="10px"
htmlFor={'type'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Select your Essay type
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="type"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeEssayType}
>
<option value="Argumentative">Argumentative</option>
<option value="Classic">Classic</option>
<option value="Persuasive">Persuasive</option>
<option value="Critique">Critique</option>
</Select>{' '}
{props.subscription ? (
<Flex direction="column">
<Text
ms="10px"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
mb="12px"
>
Looking for all features?
</Text>
<Link href="/dashboard/premium-essays">
<Flex
border="1px solid"
borderRadius={'14px'}
borderColor={borderColor}
py="14px"
mb="28px"
align="center"
px="16px"
>
<Flex
border="1px solid"
borderRadius="99px"
borderColor="secondaryGray.200"
p="10px"
h="max-content"
>
<Icon
color="brand.500"
as={MdOutlineWorkspacePremium}
h="20px"
w="20px"
/>
</Flex>
<Text
ms="10px"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
>
Try our Premium Essay Generator
</Text>
<Icon
color={textColor}
as={MdChevronRight}
h="20px"
w="20px"
ms="auto"
mb="-2px"
me="4px"
/>
</Flex>
</Link>
</Flex>
) : (
<Flex direction="column">
<Text
ms="10px"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
mb="12px"
>
Looking for more features?
</Text>
<Flex
cursor="pointer"
onClick={() => {
onOpen();
}}
border="1px solid"
borderRadius={'14px'}
borderColor={borderColor}
py="14px"
mb="28px"
align="center"
px="16px"
>
<Flex
border="1px solid"
borderRadius="99px"
borderColor="secondaryGray.200"
p="10px"
h="max-content"
>
<Icon
color="brand.500"
as={MdOutlineWorkspacePremium}
h="20px"
w="20px"
/>
</Flex>
<Text
ms="10px"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
>
Try our Premium Essay Generator
</Text>
<Icon
color={textColor}
as={MdChevronRight}
h="20px"
w="20px"
ms="auto"
mb="-2px"
me="4px"
/>
</Flex>
</Flex>
)}
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay bg="rgba(0, 0, 0, 0.85)" />
<ModalContent
mx="8px"
bg="transparent"
boxShadow="unset"
maxW="unset"
w="unset"
>
<ModalBody p="0px" position={'relative'}>
<Flex>
<Image
display={{ base: 'none', md: 'block' }}
zIndex="98"
borderLeftRadius="16px"
src={modalImage.src}
w="340px"
alt=" "
/>
<Flex
bg="white"
borderLeftRadius={{ base: '16px', md: '0px' }}
borderRightRadius="16px"
direction={'column'}
px={{ base: '30px', md: '42px' }}
py="34px"
w={{ md: '412px', lg: '456px' }}
minW={{ md: '412px', lg: '456px' }}
>
<Text
fontSize="26px"
fontWeight={'800'}
color={textColor}
mb="12px"
>
Upgrade to Unlimited
</Text>
<Text
mb="24px"
fontWeight="500"
fontSize="md"
color="gray.500"
>
Get access to all features and generate premium and
exclusive essays with our unlimited plan!
</Text>
{/* Features */}
<Flex w={{ base: '100%', xl: '80%' }} direction="column">
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Access to 12+ Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 1500 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Citation formats (APA, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
</Flex>
{/* YEARLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTJ6R3RnzmIPX',
price: 'price_1P3gMyGx8VbJPRgzkoB6Fp8F'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTJ6R3RnzmIPX'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="14px"
px="14px"
cursor="pointer"
mb="20px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="8px"
>
Yearly
</Text>
<Badge
display={{
base: 'flex',
lg: 'none',
xl: 'flex'
}}
colorScheme="green"
borderRadius="4px"
color="green.500"
textTransform={'none'}
letterSpacing="0px"
px="0px"
w="max-content"
>
Save 35%
</Badge>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$5.75
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END YEARLY */}
{/* MONTHLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTCPDFZbburMa',
price: 'price_1P3gGXGx8VbJPRgzdEZODy8K'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTCPDFZbburMa'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="16px"
px="14px"
cursor="pointer"
mb="28px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="4px"
>
Monthly
</Text>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$9
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END MONTHLY */}
{props.products.map((product: any) => {
const price = product?.prices?.find(
(price: any) => price.id === plan.price
);
if (product.id === plan.product) {
if (!price) return null;
return (
<Button
key={product.id}
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
mb="28px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
onClick={() => handleCheckout(price)}
>
Upgrade now
<Icon
as={MdChevronRight}
mt="2px"
h="16px"
w="16px"
/>
</Button>
);
}
})}
<Text
fontSize="xs"
color="gray.500"
fontWeight={'500'}
mx="auto"
mb="5px"
>
Used by 80,000+ users monthly
</Text>
<Flex direction="row" alignItems="center" mx="auto">
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="6px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Text
fontSize="sm"
fontWeight="800"
h="100%"
color={textColor}
>
4.9
</Text>
</Flex>
</Flex>
</Flex>
</ModalBody>
<ModalCloseButton
borderRadius="full"
color="#120F43"
bg="#F4F6FB !important"
_hover={{ bg: '#E9EDF6 !important' }}
_focus={{ bg: '#F4F6FB !important' }}
_active={{ bg: '#F4F6FB !important' }}
zIndex="99"
/>
</ModalContent>
</Modal>
<Button
py="20px"
px="16px"
fontSize="md"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
onClick={handleTranslate}
isLoading={loading ? true : false}
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg: 'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
>
Generate your Essay
</Button>
</Card>
<Card maxW="100%" h="100%">
<Text
fontSize={'30px'}
color={textColor}
fontWeight="800"
mb="10px"
>
AI Output
</Text>
<Text fontSize="md" color="gray.500" fontWeight="500" mb="30px">
Enjoy your outstanding essay!
</Text>
<MessageBox output={outputCode} />
<Button
variant="transparent"
border="1px solid"
borderColor={borderColor}
borderRadius="full"
maxW="160px"
ms="auto"
fontSize="md"
w={{ base: '300px', md: '420px' }}
h="54px"
onClick={() => {
if (outputCode) navigator.clipboard.writeText(outputCode);
toast({
title: outputCode
? `Essay succesfully copied!`
: `Generate an essay first!`,
position: 'top',
status: outputCode ? 'success' : `error`,
isClosable: true
});
}}
>
Copy text
</Button>
</Card>
</Flex>
</Flex>
</DashboardLayout>
);
}

View File

@@ -1,59 +0,0 @@
'use client';
import Card from '@/components/card/Card';
import LineChart from '@/components/charts/LineChart';
import { lineChartDataMain } from '@/variables/charts';
import { lineChartOptionsMain } from '@/variables/charts';
import { Flex, useColorModeValue, Text, Box, Icon } from '@chakra-ui/react';
import { MdInsights } from 'react-icons/md';
function OverallRevenue() {
const newOptions = {
...lineChartOptionsMain,
// colors: ['var(--color-500)' ],
};
const bg = useColorModeValue('secondaryGray.300', 'secondaryGray.700');
const textColor = useColorModeValue('#120F43', 'white');
const brandColor = useColorModeValue('brand.500', 'white');
return (
<Card h="381px" p="24px">
<Flex align="center" gap="12px">
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdInsights} w="24px" h="24px" />
</Flex>
<Box>
<Text as="h5" fontSize={'sm'} fontWeight="500" color="gray.700">
Credits usage in the last year
</Text>
<Text color={textColor} mt="4px" fontSize="24px" fontWeight={'700'}>
149,758
</Text>
</Box>
</Flex>
{/* Charts */}
<Flex
w="100%"
h="100%"
flex={{ sm: 'wrap', lg: 'nowrap' }}
overflow={{ '2xl': 'hidden' }}
>
<Box w="100%" h="100%">
<LineChart chartData={lineChartDataMain} chartOptions={newOptions} />
</Box>
</Flex>
</Card>
);
}
export default OverallRevenue;

View File

@@ -1,341 +0,0 @@
import Card from '@/components/card/Card';
import {
Box,
Button,
Checkbox,
Flex,
Table,
Tbody,
Td,
Text,
Th,
Thead,
Tr,
useColorModeValue,
} from '@chakra-ui/react';
import {
PaginationState,
createColumnHelper,
useReactTable,
ColumnFiltersState,
getCoreRowModel,
getFilteredRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFacetedMinMaxValues,
getPaginationRowModel,
getSortedRowModel,
flexRender,
} from '@tanstack/react-table';
import React from 'react';
import { MdChevronRight, MdChevronLeft } from 'react-icons/md';
type RowObj = {
checked?: string;
email: string;
provider: string;
created: string;
lastsigned: string;
uuid: string;
menu?: string;
};
function CheckTable(props: { tableData: any }) {
const { tableData } = props;
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = useColorModeValue('gray.700', 'white');
const borderColor = useColorModeValue('gray.200', 'gray.200');
const grayLight = useColorModeValue('gray.200', 'white');
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[],
);
let defaultData = tableData;
const [globalFilter, setGlobalFilter] = React.useState('');
// const createPages = (count: number) => {
// let arrPageCount = [];
// for (let i = 1; i <= count; i++) {
// arrPageCount.push(i);
// }
// return arrPageCount;
// };
const columns = [
columnHelper.accessor('checked', {
id: 'checked',
header: () => (
<Box w="max-content">
<Checkbox me="10px" />
</Box>
),
cell: (info: any) => (
<Flex w="max-content" alignItems="center">
<Checkbox
defaultChecked={info.getValue()[1]}
colorScheme="brand"
me="10px"
/>
</Flex>
),
}),
columnHelper.accessor('email', {
id: 'email',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
EMAIL ADDRESS
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('created', {
id: 'created',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
CREATED
</Text>
),
cell: (info: any) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('provider', {
id: 'provider',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
PROVIDER
</Text>
),
cell: (info: any) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('lastsigned', {
id: 'lastsigned',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
LAST SIGN IN
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('uuid', {
id: 'uuid',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
USER UID
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
]; // eslint-disable-next-line
const [data, setData] = React.useState(() => [...defaultData]);
const [{ pageIndex, pageSize }, setPagination] =
React.useState<PaginationState>({
pageIndex: 0,
pageSize: 11,
});
const pagination = React.useMemo(
() => ({
pageIndex,
pageSize,
}),
[pageIndex, pageSize],
);
const table = useReactTable({
data,
columns,
state: {
columnFilters,
globalFilter,
pagination,
},
onPaginationChange: setPagination,
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues(),
debugTable: true,
debugHeaders: true,
debugColumns: false,
});
return (
<Card w="100%" h="100%" overflow={'auto'} p="0px">
<Box mt="20px" overflowX={{ base: 'scroll', xl: 'hidden' }}>
<Table w="100%">
<Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr
key={headerGroup.id}
borderBottom="1px solid"
borderColor="gray.200"
p="20px"
>
{headerGroup.headers.map((header) => {
return (
<Th
key={header.id}
colSpan={header.colSpan}
onClick={header.column.getToggleSortingHandler()}
cursor="pointer"
borderBottom="1px solid"
borderColor={borderColor}
pb="14px"
ps="24px"
pe="16px"
textAlign={'start'}
>
<Flex
alignItems={'center'}
justifyContent="space-between"
fontSize="12px"
color={textColorSecondary}
// gray 1
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: '',
desc: '',
}[header.column.getIsSorted() as string] ?? null}
</Flex>
</Th>
);
})}
</Tr>
))}
</Thead>
<Tbody>
{table
.getRowModel()
.rows.slice(0, 7)
.map((row) => {
return (
<Tr key={row.id} px="24px">
{row.getVisibleCells().map((cell) => {
return (
<Td
key={cell.id}
w="max-content"
borderBottom="1px solid"
borderColor={borderColor}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Td>
);
})}
</Tr>
);
})}
</Tbody>
</Table>
{/* pagination */}
<Flex
mt="8px"
w="100%"
h="80px"
alignItems={'center'}
justifyContent="space-between"
px="24px"
>
{/* left side */}
<Flex alignItems={'center'} gap="12px">
<Text color={textColorSecondary} fontWeight="500" fontSize="sm">
Showing 6 rows per page
</Text>
</Flex>
{/* right side */}
<Flex alignItems="center" gap="8px">
<Button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
variant="transparent"
display={'flex'}
alignItems="center"
justifyContent="center"
borderRadius="full"
bg="transparent"
p="8px"
fontSize={'18px'}
color="gray.700"
>
<MdChevronLeft />
</Button>
<Button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
variant="transparent"
display={'flex'}
alignItems="center"
justifyContent="center"
borderRadius="full"
bg="transparent"
p="8px"
fontSize={'18px'}
color="gray.700"
>
<MdChevronRight />
</Button>
</Flex>
</Flex>
</Box>
</Card>
);
}
export default CheckTable;
const columnHelper = createColumnHelper<RowObj>();

View File

@@ -1,49 +0,0 @@
import Card from '@/components/card/Card';
import { Box, Flex, Text, useColorModeValue } from '@chakra-ui/react';
const Statistics = (props: {
icon?: JSX.Element;
title: string;
value: number | string;
endContent?: JSX.Element;
}) => {
const { icon, title, value, endContent } = props;
const textColorSecondary = useColorModeValue('gray.700', 'white');
const textColor = useColorModeValue('#120F43', 'white');
return (
<Card
w="100%"
justifyContent="space-between"
borderRadius="14px"
bg="white"
py="30px"
>
<Flex gap="12px" alignItems={'center'}>
{icon}
<Box>
<Text
as="h5"
fontSize="sm"
fontWeight={'500'}
color={textColorSecondary}
>
{title}
</Text>
<Text
color={textColor}
fontWeight="700"
mt="4px"
fontSize="24px"
lineHeight={'24px'}
>
{value}
</Text>
</Box>
</Flex>
{endContent}
</Card>
);
};
export default Statistics;

View File

@@ -1,144 +0,0 @@
/*eslint-disable*/
'use client';
import MainChart from '@/components/dashboard/main/cards/MainChart';
import MainDashboardTable from '@/components/dashboard/main/cards/MainDashboardTable';
import Statistics from '@/components/dashboard/main/cards/Statistics';
import DashboardLayout from '@/components/layout';
import { Database } from '@/types_db';
import tableDataUserReports from '@/variables/tableDataUserReports';
import { Box, Flex, Grid, Icon, useColorModeValue } from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { HiOutlineChip } from 'react-icons/hi';
import { MdOutlineGroup, MdOutlineGroupAdd, MdKey } from 'react-icons/md';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null | any;
userDetails: { [x: string]: any } | null | any;
}
export default function Main(props: Props) {
const bg = useColorModeValue('secondaryGray.300', 'whiteAlpha.200');
const brandColor = useColorModeValue('brand.500', 'white');
console.log(props.user);
return (
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Main Dashboard"
description="Manage your dashboard"
>
<Box h="100%" w="100%">
<Grid
mb="20px"
w="100%"
gridTemplateColumns={{
base: 'repeat(1, minmax(0, 1fr))',
md: 'repeat(2, minmax(0, 1fr))',
xl: 'repeat(4, minmax(0, 1fr))'
}}
borderRadius="14px"
gap="20px"
>
{/* statistics */}
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdOutlineGroup} w="24px" h="24px" />
</Flex>
}
title="Credits used in the last month"
value="46,042"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdOutlineGroupAdd} w="24px" h="24px" />
</Flex>
}
title="Total Credits"
value="149,758"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={HiOutlineChip} w="24px" h="24px" />
</Flex>
}
title="Plan Credits"
value="100,000"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdKey} w="24px" h="24px" />
</Flex>
}
title="Current Plan"
value="Expert+"
/>
</Grid>
<Box mb="20px">
<MainChart />
</Box>
{/* Conversion and talbes*/}
<Box w="full" h="full" borderRadius="14px">
<MainDashboardTable tableData={tableDataUserReports} />
</Box>
</Box>
</DashboardLayout>
);
}

View File

@@ -1,14 +0,0 @@
import { getUser } from '@/utils/supabase/queries';
import { redirect } from 'next/navigation';
import { createClient } from '@/utils/supabase/server';
export default async function Dashboard() {
const supabase = createClient();
const [user] = await Promise.all([getUser(supabase)]);
if (!user) {
return redirect('/dashboard/signin');
} else {
redirect('/dashboard/main');
}
}

View File

@@ -1,534 +0,0 @@
/*eslint-disable*/
'use client';
import MessageBox from '@/components/MessageBox';
import Card from '@/components/card/Card';
import DashboardLayout from '@/components/layout';
import { OpenAIModel, PremiumEssayBody } from '@/types/types';
import { Database } from '@/types_db';
import {
Button,
Flex,
FormLabel,
Select,
Switch,
Text,
Textarea,
useColorModeValue,
useToast
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { useState } from 'react';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
export default function PremiumEssayGenerator(props: Props) {
// Input States
const [words, setWords] = useState<string>('200-300');
const [essayType, setEssayType] = useState<
| ''
| 'Argumentative'
| 'Classic'
| 'Persuasive'
| 'Memoir'
| 'Critique'
| 'Compare/Contrast'
| 'Narrative'
| 'Descriptive'
| 'Expository'
| 'Cause and Effect'
| 'Reflective'
| 'Informative'
>('');
const [topic, setTopic] = useState<string>('');
const [tone, setTone] = useState<string>('');
const [citation, setCitation] = useState<string>('');
const [citations, setCitations] = useState(false);
const [level, setLevel] = useState<string>('');
// Response message
const [outputCode, setOutputCode] = useState<string>('');
// ChatGPT model
const [model, setModel] = useState<OpenAIModel>('gpt-3.5-turbo');
// Loading state
const [loading, setLoading] = useState<boolean>(false);
// API Key
// const [apiKey, setApiKey] = useState<any>();
const textColor = useColorModeValue('#120F43', 'white');
const placeholderColor = useColorModeValue(
{ color: 'gray.500' },
{ color: 'whiteAlpha.600' }
);
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
const toast = useToast();
// -------------- Main API Handler --------------
const handleTranslate = async () => {
const maxCodeLength = model === 'gpt-3.5-turbo' ? 700 : 700;
// Chat post conditions(maximum number of characters, valid message etc.)
if (!topic) {
alert('Please enter your subject.');
return;
}
if (!essayType) {
alert('Please choose a type of essay');
return;
}
if (!tone) {
alert('Please choose a essay tone');
return;
}
if (!citation) {
alert('Please choose a citation format');
return;
}
if (!level) {
alert('Please choose an level');
return;
}
if (topic.length > maxCodeLength) {
alert(
`Please enter a topic less than ${maxCodeLength} characters. You are currently at ${topic.length} characters.`
);
return;
}
setLoading(true);
setOutputCode('');
const controller = new AbortController();
const body: PremiumEssayBody = {
words,
topic,
essayType,
tone,
citation,
level,
citations,
model
};
// -------------- Fetch --------------
const response = await fetch('/api/premiumEssayAPI', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
signal: controller.signal,
body: JSON.stringify(body)
});
if (!response.ok) {
setLoading(false);
if (response) {
alert(
'Something went wrong went fetching from the API. Make sure to use a valid API key.'
);
}
return;
}
const data = response.body;
if (!data) {
setLoading(false);
alert('Something went wrong');
return;
}
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
let code = '';
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
code += chunkValue;
setOutputCode((prevCode) => prevCode + chunkValue);
}
setLoading(false);
copyToClipboard(code);
};
// -------------- Copy Response --------------
const copyToClipboard = (text: string) => {
const el = document.createElement('textarea');
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
// *** Initializing apiKey with .env.local value
// useEffect(() => {
// ENV file verison
// const apiKeyENV = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
// if (apiKey === undefined || null) {
// setApiKey(apiKeyENV);
// }
// }, []);
// -------------- Input Value Handler --------------
const handleChangeWords = (Event: any) => {
setWords(Event.target.value);
};
const handleChange = (Event: any) => {
setTopic(Event.target.value);
};
const handleChangeEssayType = (Event: any) => {
setEssayType(Event.target.value);
};
const handleChangeEssayTone = (Event: any) => {
setTone(Event.target.value);
};
const handleChangeCitation = (Event: any) => {
setCitation(Event.target.value);
};
const handleChangeLevel = (Event: any) => {
setLevel(Event.target.value);
};
const handleCitations = (Event: any) => {
setCitations(!citations);
};
return (
<>
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Premium Generator"
description="Premium Generator"
>
<Flex
w="100%"
direction="column"
position="relative"
mt={{ base: '70px', md: '0px', xl: '0px' }}
>
<Flex
mx="auto"
w={{ base: '100%', md: '100%', xl: '100%' }}
maxW="100%"
justify="center"
direction={{ base: 'column', md: 'row' }}
>
<Card
minW={{ base: '100%', md: '40%', xl: '476px' }}
maxW={{ base: '100%', md: '40%', xl: '476px' }}
h="min-content"
me={{ base: '0px', md: '20px' }}
mb={{ base: '20px', md: '0px' }}
>
<Text
fontSize={'30px'}
color={textColor}
fontWeight="800"
mb="10px"
>
Essay Topic
</Text>
<Text fontSize="md" color="gray.500" fontWeight="500" mb="30px">
What your premium essay will be about?
</Text>
<Textarea
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
p="15px 20px"
mb="28px"
minH="124px"
fontWeight="500"
_focus={{ borderColor: 'none' }}
color={textColor}
placeholder="Type here your topic..."
_placeholder={placeholderColor}
onChange={handleChange}
/>
<FormLabel
display="flex"
ms="10px"
htmlFor={'words'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Number of Words
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="words"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeWords}
>
<option value="200-300">200-300</option>
<option value="300-400">300-400</option>
<option value="400-500">400-500</option>
<option value="500-600">500-600</option>
<option value="700-900">700-900</option>
<option value="1000-1500">1000-1500</option>
</Select>
<FormLabel
display="flex"
ms="10px"
htmlFor={'type'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Select your Essay type
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="type"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeEssayType}
>
<option value="Argumentative">Argumentative</option>
<option value="Classic">Classic</option>
<option value="Compare/Contrast">Compare/Contrast</option>
<option value="Persuasive">Persuasive</option>
<option value="Critique">Critique</option>
<option value="Memoir">Memoir</option>
<option value="Narrative">Narrative</option>
<option value="Descriptive">Descriptive</option>
<option value="Expository">Expository</option>
<option value="Cause and Effect">Cause and Effect</option>
<option value="Reflective">Reflective</option>
<option value="Informative">Informative</option>
</Select>
<FormLabel
display="flex"
ms="10px"
htmlFor={'tone'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Select your Essay Tone
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="tone"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeEssayTone}
>
<option value="Academic">Academic</option>
<option value="Sarcastic">Sarcastic</option>
<option value="Informal">Informal</option>
<option value="Assertive">Assertive</option>
<option value="Friendly">Friendly</option>
<option value="Humorous">Humorous</option>
<option value="Formal">Formal</option>
</Select>
<FormLabel
display="flex"
ms="10px"
htmlFor={'citation'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Select your Citation Format
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="citation"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeCitation}
>
<option value="Cambridge Style">Cambridge Style</option>
<option value="Harvard Style">Harvard Style</option>
<option value="MLA">MLA</option>
<option value="Chicago Style">Chicago Style</option>
<option value="APA">APA</option>
<option value="AMA">AMA</option>
<option value="Oxford Style">Oxford Style</option>
<option value="IEEE">IEEE</option>
<option value="CSE">CSE</option>
<option value="Bluebook">Bluebook</option>
<option value="Turabian">Turabian</option>
<option value="Vancouver">Vancouver</option>
<option value="ACS">ACS</option>
<option value="NLM">NLM</option>
<option value="AAA">AAA</option>
<option value="ASA">ASA</option>
<option value="APSA">APSA</option>
</Select>
<FormLabel
display="flex"
ms="10px"
htmlFor={'level'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Academic Level
</FormLabel>
<Select
border="1px solid"
borderRadius={'10px'}
borderColor={borderColor}
h="60px"
id="level"
placeholder="Select option"
_focus={{ borderColor: 'none' }}
mb="28px"
onChange={handleChangeLevel}
>
<option value="High-School">High-School</option>
<option value="Pre Final">Pre Final</option>
<option value="Master">Master</option>
<option value="Doctoral">Doctoral</option>
<option value="Final Year">Final Year</option>
</Select>
<Flex
mb="28px"
align={{ base: 'unset', md: 'center' }}
direction={{ base: 'column', md: 'row' }}
>
<FormLabel
display="flex"
ms="10px"
me={{ base: '0px', md: '20px' }}
mb={{ base: '10px', md: '0px' }}
htmlFor={'citations'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
>
Citations and refrences
</FormLabel>
<Switch
isChecked={citations}
onChange={handleCitations}
colorScheme="brandScheme"
id="citations"
/>
</Flex>
<Button
py="20px"
px="16px"
fontSize="md"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
onClick={handleTranslate}
isLoading={loading ? true : false}
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
>
Generate your Essay
</Button>
</Card>
<Card maxW="100%" h="100%">
<Text
fontSize={'30px'}
color={textColor}
fontWeight="800"
mb="10px"
>
AI Output
</Text>
<Text fontSize="md" color="gray.500" fontWeight="500" mb="30px">
Enjoy your outstanding essay!
</Text>
<MessageBox output={outputCode} />
<Button
variant="transparent"
border="1px solid"
borderColor={borderColor}
borderRadius="full"
maxW="160px"
ms="auto"
fontSize="md"
w={{ base: '300px', md: '420px' }}
h="54px"
onClick={() => {
if (outputCode) navigator.clipboard.writeText(outputCode);
toast({
title: outputCode
? `Essay succesfully copied!`
: `Generate an essay first!`,
position: 'top',
status: outputCode ? 'success' : `error`,
isClosable: true
});
}}
>
Copy text
</Button>
</Card>
</Flex>
</Flex>
</DashboardLayout>
</>
);
}

View File

@@ -1,308 +0,0 @@
/*eslint-disable*/
'use client';
// import ManageSubscriptionButton from './ManageSubscriptionButton';
import Card from '@/components/card/Card';
import DashboardLayout from '@/components/layout';
import { HSeparator } from '@/components/separator/Separator';
import { Database } from '@/types_db';
import { handleRequest } from '@/utils/auth-helpers/client';
import { updateEmail, updateName } from '@/utils/auth-helpers/server';
import {
Button,
Flex,
FormLabel,
Input,
Text,
useColorModeValue
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { redirect, useRouter } from 'next/navigation';
import { useState } from 'react';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
export default function Settings(props: Props) {
const [isSubmitting, setIsSubmitting] = useState(false);
const router = useRouter();
const textColor = useColorModeValue('#120F43', 'white');
const placeholderColor = useColorModeValue(
{ color: 'gray.500' },
{ color: 'whiteAlpha.600' }
);
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.200');
// -------------- Input Value Handler --------------
const handleSubmitEmail = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true);
// Check if the new email is the same as the old email
if (e.currentTarget.newEmail.value === props.user.email) {
e.preventDefault();
setIsSubmitting(false);
return;
}
handleRequest(e, updateEmail, router);
setIsSubmitting(false);
};
const handleSubmitName = async (e: React.FormEvent<HTMLFormElement>) => {
setIsSubmitting(true);
// Check if the new name is the same as the old name
if (e.currentTarget.fullName.value === props.user.user_metadata.full_name) {
e.preventDefault();
setIsSubmitting(false);
return;
}
handleRequest(e, updateName, router);
setIsSubmitting(false);
};
if (!props.user) {
return redirect('/dashboard/signin');
}
return (
<>
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Account Settings"
description="Profile settings."
>
<Flex
w="100%"
direction="column"
position="relative"
mt={{ base: '70px', md: '0px', xl: '0px' }}
>
<Flex
mx="auto"
w={{ base: '100%', md: '100%', xl: '100%' }}
maxW="100%"
justify="center"
direction={{ base: 'column', md: 'row' }}
>
<Card
// minW={{ base: '100%' }}
maxW={{ base: '100%' }}
px={{ base: '10px', md: '20px', lg: '20px' }}
py={{ base: '28px', md: '20px', lg: '30px' }}
w="820px"
h="min-content"
me={{ base: '0px', md: '20px' }}
mb={{ base: '20px', md: '0px' }}
>
<Text
ps={{ base: '10px', md: '32px' }}
fontSize={{ base: 'lg', md: '30px' }}
color={textColor}
fontWeight="800"
>
Account Settings
</Text>
<Text
ps={{ base: '10px', md: '32px' }}
fontSize={{ base: 'sm', md: 'md' }}
color="gray.500"
fontWeight="500"
mb="30px"
>
Here you can change your account information
</Text>
<FormLabel
px={{ base: '10px', md: '32px' }}
display="flex"
ms="10px"
htmlFor={'fullName'}
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
lineHeight="100%"
mb="12px"
>
Your Name
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
>
{' '}
(30 characters maximum)
</Text>
</FormLabel>
<Flex
direction={{ base: 'column', md: 'row' }}
px={{ base: '10px', md: '32px' }}
mb={{ base: '30px', md: '0px' }}
>
<form
style={{ width: '100%' }}
id="nameForm"
onSubmit={(e) => handleSubmitName(e)}
>
<Input
color={textColor}
border="1px solid"
borderRadius={'45px'}
borderColor={borderColor}
h="60px"
type="text"
name="fullName"
id="fullName"
defaultValue={props.user?.user_metadata.full_name ?? ''}
fontWeight="500"
placeholder="Please enter your full name"
_placeholder={placeholderColor}
_focus={{ borderColor: 'none' }}
mb={{ base: '14px', md: '26px' }}
me="20px"
/>
</form>
<Button
py="20px"
px="16px"
fontSize="sm"
ms="10px"
variant="primary"
borderRadius="45px"
h="54px"
form="nameForm"
type="submit"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
minW="150px"
>
Update name
</Button>
<HSeparator
bg="gray.200"
mt={{ base: '30px', md: '0px' }}
display={{ md: 'none' }}
alignSelf="center"
maxW="90%"
/>
</Flex>
{/* <Text
px={{ base: '10px', md: '36px' }}
color="red"
mb="20px"
display={nameError?.status ? 'block' : 'none'}
>
{nameError?.message}
</Text> */}
<FormLabel
px={{ base: '10px', md: '32px' }}
display="flex"
htmlFor={'email'}
fontSize="md"
flexDirection={{ base: 'column', md: 'row' }}
color={textColor}
letterSpacing="0px"
fontWeight="bold"
_hover={{ cursor: 'pointer' }}
lineHeight="100%"
mb="12px"
>
Your Email
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms={{ base: '0px', md: '4px' }}
mt={{ base: '6px', md: '0px' }}
>
{' '}
(We will email you to verify the change)
</Text>
</FormLabel>
<Flex
direction={{ base: 'column', md: 'row' }}
px={{ base: '10px', md: '32px' }}
>
<form
style={{ width: '100%' }}
id="emailForm"
onSubmit={(e) => handleSubmitEmail(e)}
>
<Input
type="text"
name="newEmail"
id="email"
color={textColor}
border="1px solid"
borderRadius={'45px'}
borderColor={borderColor}
h="60px"
fontWeight="500"
placeholder="Please enter your email"
_placeholder={placeholderColor}
_focus={{ borderColor: 'none' }}
defaultValue={props.user.email ?? ''}
mb={{ base: '14px', md: '26px' }}
me="20px"
/>
</form>
<Button
py="20px"
px="16px"
fontSize="sm"
type="submit"
form="emailForm"
variant="primary"
borderRadius="45px"
ms="10px"
h="54px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
minW="150px"
>
Update email
</Button>
</Flex>
</Card>
</Flex>
</Flex>
</DashboardLayout>
</>
);
}

View File

@@ -1,263 +0,0 @@
/*eslint-disable*/
'use client';
import Card from '@/components/card/Card';
import DashboardLayout from '@/components/layout';
import { Database } from '@/types_db';
import { createStripePortal } from '@/utils/stripe/server';
import { Badge, Button, Flex, Icon, Link, Text } from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { redirect, usePathname, useRouter } from 'next/navigation';
import { useState } from 'react';
import { MdChevronRight } from 'react-icons/md';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null | any;
userDetails: { [x: string]: any } | null | any;
}
export default function Subscription(props: Props) {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
const currentPath = usePathname();
const handleStripePortalRequest = async () => {
setIsSubmitting(true);
const redirectUrl = await createStripePortal(currentPath);
setIsSubmitting(false);
return router.push(redirectUrl);
};
if (!props.user) {
return redirect('/dashboard/signin');
}
return (
<>
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Subscription Page"
description="Manage your subscriptions"
>
<Flex
w="100%"
direction="column"
position="relative"
mt={{ base: '70px', md: '0px', xl: '0px' }}
>
<Flex
mx="auto"
w={{ base: '100%', md: '100%', xl: '100%' }}
maxW="100%"
justify="center"
direction={{ base: 'column', md: 'row' }}
>
<Card w="830px" maxW={{ base: '100%' }} h="min-content">
<Card
bg="linear-gradient(15deg, #4A25E1 26.3%, #7B5AFF 86.4%)"
maxW={{ base: '100%' }}
px={{ base: '20px', md: '40px', lg: '50px' }}
py={{ base: '28px', md: '40px', lg: '50px' }}
me={{ base: '0px', md: '20px' }}
mb="16px"
>
<Badge
w="max-content"
mb="10px"
fontSize="sm"
bg="rgba(255,255,255,0.12)"
color="white"
fontWeight="bold"
borderRadius="8px"
>
CURRENT PLAN
</Badge>
{props.subscription ? (
props.products?.map((product: any) => {
const price = product?.prices?.find(
(price: any) => price.id === props.subscription?.price_id
);
// {props.subscription?.map((subscription:any) => {
// const price = subscription?.prices?.find(
// (user:any) => user.id === props?.userDetails.id,
// );
if (price?.id === props.subscription.price_id)
return (
// IN CASE USER HAS PLAN
<Flex
justifyContent="space-between"
direction={{ base: 'column', md: 'row' }}
>
<Flex direction="column">
<Text
fontSize={{ base: '30px', md: '44px' }}
color="white"
fontWeight="800"
>
{product?.name
? product.name?.toString()
: 'No plan active'}
</Text>
<Text
fontSize={{ base: 'sm', md: '20px' }}
color="white"
fontWeight="500"
mb={{ base: '20px', md: '0px' }}
>
{product?.name
? `You are currently on ${product.name?.toString()}`
: "You don't have an active subscription."}
</Text>
</Flex>
<Flex direction="column">
<Text
fontSize={{ base: 'lg', md: '24px' }}
color="white"
textAlign={{ base: 'left', md: 'right' }}
fontWeight="800"
mb="10px"
>
$
{price?.unit_amount !== null
? price?.unit_amount / 100
: '0'}
{price?.interval === 'year'
? '/year'
: price?.interval === 'month'
? '/month'
: 'error'}
</Text>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="outline"
borderRadius="45px"
w={{ base: '100%', md: '266px' }}
h="54px"
onClick={handleStripePortalRequest}
>
{props?.subscription
? 'Manage your subscription'
: 'See pricing Plans'}
<Icon
as={MdChevronRight}
display={props?.subscription ? 'none' : 'unset'}
mt="2px"
h="16px"
w="16px"
/>
</Button>
</Flex>
</Flex>
);
})
) : (
// IN CASE OF NOW PLAN
<Flex
justifyContent="space-between"
direction={{ base: 'column', md: 'row' }}
>
<Flex direction="column">
<Text
fontSize={{ base: '30px', md: '44px' }}
color="white"
fontWeight="800"
>
No plan active
</Text>
<Text
fontSize={{ base: 'sm', md: '20px' }}
color="white"
fontWeight="500"
mb={{ base: '20px', md: '0px' }}
>
You don't have an active subscription.
</Text>
</Flex>
<Flex direction="column">
<Text
fontSize={{ base: 'lg', md: '24px' }}
color="white"
textAlign={{ base: 'left', md: 'right' }}
fontWeight="800"
mb="10px"
>
$0/month
</Text>
<Link href="/pricing">
<Button
py="20px"
px="16px"
fontSize="sm"
variant="outline"
borderRadius="45px"
w={{ base: '100%', md: '190px' }}
h="54px"
>
See pricing Plans
<Icon
as={MdChevronRight}
mt="2px"
h="16px"
w="16px"
/>
</Button>
</Link>
</Flex>
</Flex>
)}
</Card>
<Flex
direction={{ base: 'column', md: 'row' }}
justifyContent="center"
>
<Text
textAlign={'center'}
fontWeight={'500'}
fontSize="sm"
alignSelf="center"
color="gray.500"
w={{ base: '70%', md: 'unset' }}
me="2px"
>
Got a question regarding your subscription? Chat with us via{' '}
</Text>
<Link href="mailto:hello@horizon-ui.com">
<Text
textAlign={'center'}
fontWeight={'500'}
fontSize="sm"
textDecoration="underline"
color="gray.500"
>
hello@horizon-ui.com.
</Text>
</Link>
</Flex>
</Card>
</Flex>
</Flex>
</DashboardLayout>
</>
);
}

View File

@@ -1,49 +0,0 @@
import Card from '@/components/card/Card';
import { Box, Flex, Text, useColorModeValue } from '@chakra-ui/react';
const Statistics = (props: {
icon?: JSX.Element;
title: string;
value: number | string;
endContent?: JSX.Element;
}) => {
const { icon, title, value, endContent } = props;
const textColorSecondary = useColorModeValue('gray.700', 'white');
const textColor = useColorModeValue('#120F43', 'white');
return (
<Card
w="100%"
justifyContent="space-between"
borderRadius="14px"
bg="white"
py="30px"
>
<Flex gap="12px" alignItems={'center'}>
{icon}
<Box>
<Text
as="h5"
fontSize="sm"
fontWeight={'500'}
color={textColorSecondary}
>
{title}
</Text>
<Text
color={textColor}
fontWeight="700"
mt="4px"
fontSize="24px"
lineHeight={'24px'}
>
{value}
</Text>
</Box>
</Flex>
{endContent}
</Card>
);
};
export default Statistics;

View File

@@ -1,341 +0,0 @@
import Card from '@/components/card/Card';
import {
Box,
Button,
Checkbox,
Flex,
Table,
Tbody,
Td,
Text,
Th,
Thead,
Tr,
useColorModeValue,
} from '@chakra-ui/react';
import {
PaginationState,
createColumnHelper,
useReactTable,
ColumnFiltersState,
getCoreRowModel,
getFilteredRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFacetedMinMaxValues,
getPaginationRowModel,
getSortedRowModel,
flexRender,
} from '@tanstack/react-table';
import React from 'react';
import { MdChevronRight, MdChevronLeft } from 'react-icons/md';
type RowObj = {
checked?: string;
email: string;
provider: string;
created: string;
lastsigned: string;
uuid: string;
menu?: string;
};
function CheckTable(props: { tableData: any }) {
const { tableData } = props;
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = useColorModeValue('gray.700', 'white');
const borderColor = useColorModeValue('gray.200', 'gray.200');
const grayLight = useColorModeValue('gray.200', 'white');
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[],
);
let defaultData = tableData;
const [globalFilter, setGlobalFilter] = React.useState('');
// const createPages = (count: number) => {
// let arrPageCount = [];
// for (let i = 1; i <= count; i++) {
// arrPageCount.push(i);
// }
// return arrPageCount;
// };
const columns = [
columnHelper.accessor('checked', {
id: 'checked',
header: () => (
<Box w="max-content">
<Checkbox me="10px" />
</Box>
),
cell: (info: any) => (
<Flex w="max-content" alignItems="center">
<Checkbox
defaultChecked={info.getValue()[1]}
colorScheme="brand"
me="10px"
/>
</Flex>
),
}),
columnHelper.accessor('email', {
id: 'email',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
EMAIL ADDRESS
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('created', {
id: 'created',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
CREATED
</Text>
),
cell: (info: any) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('provider', {
id: 'provider',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
PROVIDER
</Text>
),
cell: (info: any) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('lastsigned', {
id: 'lastsigned',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
LAST SIGN IN
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
columnHelper.accessor('uuid', {
id: 'uuid',
header: () => (
<Text
justifyContent="space-between"
align="center"
fontSize={{ sm: '10px', lg: '12px' }}
color="gray.500"
>
USER UID
</Text>
),
cell: (info) => (
<Text color={textColor} fontSize="sm" fontWeight="600">
{info.getValue()}
</Text>
),
}),
]; // eslint-disable-next-line
const [data, setData] = React.useState(() => [...defaultData]);
const [{ pageIndex, pageSize }, setPagination] =
React.useState<PaginationState>({
pageIndex: 0,
pageSize: 11,
});
const pagination = React.useMemo(
() => ({
pageIndex,
pageSize,
}),
[pageIndex, pageSize],
);
const table = useReactTable({
data,
columns,
state: {
columnFilters,
globalFilter,
pagination,
},
onPaginationChange: setPagination,
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues(),
debugTable: true,
debugHeaders: true,
debugColumns: false,
});
return (
<Card w="100%" h="100%" overflow={'auto'} p="0px">
<Box mt="20px" overflowX={{ base: 'scroll', xl: 'hidden' }}>
<Table w="100%">
<Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr
key={headerGroup.id}
borderBottom="1px solid"
borderColor="gray.200"
p="20px"
>
{headerGroup.headers.map((header) => {
return (
<Th
key={header.id}
colSpan={header.colSpan}
onClick={header.column.getToggleSortingHandler()}
cursor="pointer"
borderBottom="1px solid"
borderColor={borderColor}
pb="14px"
ps="24px"
pe="16px"
textAlign={'start'}
>
<Flex
alignItems={'center'}
justifyContent="space-between"
fontSize="12px"
color={textColorSecondary}
// gray 1
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: '',
desc: '',
}[header.column.getIsSorted() as string] ?? null}
</Flex>
</Th>
);
})}
</Tr>
))}
</Thead>
<Tbody>
{table
.getRowModel()
.rows.slice(0, 7)
.map((row) => {
return (
<Tr key={row.id} px="24px">
{row.getVisibleCells().map((cell) => {
return (
<Td
key={cell.id}
w="max-content"
borderBottom="1px solid"
borderColor={borderColor}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Td>
);
})}
</Tr>
);
})}
</Tbody>
</Table>
{/* pagination */}
<Flex
mt="8px"
w="100%"
h="80px"
alignItems={'center'}
justifyContent="space-between"
px="24px"
>
{/* left side */}
<Flex alignItems={'center'} gap="12px">
<Text color={textColorSecondary} fontWeight="500" fontSize="sm">
Showing 6 rows per page
</Text>
</Flex>
{/* right side */}
<Flex alignItems="center" gap="8px">
<Button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
variant="transparent"
display={'flex'}
alignItems="center"
justifyContent="center"
borderRadius="full"
bg="transparent"
p="8px"
fontSize={'18px'}
color="gray.700"
>
<MdChevronLeft />
</Button>
<Button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
variant="transparent"
display={'flex'}
alignItems="center"
justifyContent="center"
borderRadius="full"
bg="transparent"
p="8px"
fontSize={'18px'}
color="gray.700"
>
<MdChevronRight />
</Button>
</Flex>
</Flex>
</Box>
</Card>
);
}
export default CheckTable;
const columnHelper = createColumnHelper<RowObj>();

View File

@@ -1,144 +0,0 @@
/*eslint-disable*/
'use client';
import Statistics from '@/components/dashboard/users-list/cards/Statistics';
import UserListTable from '@/components/dashboard/users-list/cards/UserListTable';
import DashboardLayout from '@/components/layout';
import { Database } from '@/types_db';
import tableDataUserReports from '@/variables/tableDataUserReports';
import { Box, Flex, Grid, Icon, useColorModeValue } from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { redirect } from 'next/navigation';
import { MdOutlineGroup, MdOutlineGroupAdd, MdKey } from 'react-icons/md';
import { TbDatabase } from 'react-icons/tb';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null | any;
userDetails: { [x: string]: any } | null | any;
}
export default function Settings(props: Props) {
if (!props.user) {
return redirect('/dashboard/signin');
}
const bg = useColorModeValue('secondaryGray.300', 'whiteAlpha.200');
const brandColor = useColorModeValue('brand.500', 'white');
return (
<DashboardLayout
userDetails={props.userDetails}
user={props?.user}
products={props.products}
subscription={props.subscription}
title="Subscription Page"
description="Manage your subscriptions"
>
<Box mt="12px" h="100%" w="100%">
<Grid
mb="20px"
gap="20px"
gridTemplateColumns={{
base: 'repeat(1, minmax(0, 1fr))',
md: 'repeat(2, minmax(0, 1fr))',
xl: 'repeat(4, minmax(0, 1fr))'
}}
borderRadius="14px"
>
{/* statistics */}
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdOutlineGroup} w="24px" h="24px" />
</Flex>
}
title="Total Users"
value="9,794"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdOutlineGroupAdd} w="24px" h="24px" />
</Flex>
}
title="Users Today"
value="379"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={TbDatabase} w="24px" h="24px" />
</Flex>
}
title="REST Requests"
value="270,307"
/>
<Statistics
icon={
<Flex
h={'56px'}
w={'56px'}
justifyContent="center"
alignItems={'center'}
rounded="full"
fontSize="36px"
color={brandColor}
bg={bg}
>
<Icon as={MdKey} w="24px" h="24px" />
</Flex>
}
title="Auth Requests"
value="23,484"
/>
</Grid>
{/* Conversion and talbes*/}
<Flex h="100%" w="100%" borderRadius="14px">
<UserListTable tableData={tableDataUserReports} />
</Flex>
</Box>
</DashboardLayout>
);
}

View File

@@ -1,87 +0,0 @@
'use client';
/*eslint-disable*/
import Link from '@/components/link/Link';
import {
Flex,
List,
ListItem,
Text,
useColorModeValue,
} from '@chakra-ui/react';
export default function Footer() {
const textColor = useColorModeValue('gray.500', 'white');
return (
<Flex
zIndex="3"
flexDirection={{
base: 'column',
xl: 'row',
}}
alignItems="center"
justifyContent="space-between"
px={{ base: '30px', md: '50px' }}
pb="30px"
>
<Text
color={textColor}
fontSize={{ base: 'xs', md: 'sm' }}
textAlign={{
base: 'center',
xl: 'start',
}}
fontWeight="500"
mb={{ base: '10px', xl: '0px' }}
>
{' '}
&copy; {new Date().getFullYear()}
<Text as="span" fontWeight="500" ms="4px">
Horizon UI Boilerplate. All Rights Reserved.
</Text>
</Text>
<List display="flex">
<ListItem
me={{
base: '10px',
md: '44px',
}}
>
<Link
fontWeight="500"
fontSize={{ base: 'xs', md: 'sm' }}
color={textColor}
href="https://horizon-ui.com"
>
Homepage
</Link>
</ListItem>
<ListItem
me={{
base: '10px',
md: '44px',
}}
>
<Link
fontWeight="500"
fontSize={{ base: 'xs', md: 'sm' }}
color={textColor}
href="https://horizon-ui.notion.site/Terms-Conditions-6e79229d25ed48f48a481962bc6de3ee"
>
Terms of Use
</Link>
</ListItem>
<ListItem>
<Link
fontWeight="500"
fontSize={{ base: 'xs', md: 'sm' }}
color={textColor}
href="https://horizon-ui.notion.site/Privacy-Policy-8addde50aa8e408ca5c5f5811c38f971"
>
Privacy Policy
</Link>
</ListItem>
</List>
</Flex>
);
}

View File

@@ -1,80 +0,0 @@
'use client';
/*eslint-disable*/
import {
Flex,
Link,
List,
ListItem,
useColorModeValue
} from '@chakra-ui/react';
export default function Footer() {
let textColor = useColorModeValue('gray.500', 'white');
return (
<Flex
mt="auto"
zIndex="3"
flexDirection={{
base: 'column',
lg: 'row'
}}
alignItems="center"
justifyContent="space-between"
px={{ base: '30px', md: '0px' }}
pb="30px"
>
<List
display="flex"
flexDirection={{
base: 'row',
md: 'row'
}}
>
<ListItem
me={{
base: '16px',
md: '44px'
}}
>
<Link
fontWeight="500"
fontSize={{ base: '10px', md: 'sm' }}
color={textColor}
isExternal
href="https://horizon-ui.notion.site/Terms-Conditions-6e79229d25ed48f48a481962bc6de3ee"
>
Terms & Conditions
</Link>
</ListItem>
<ListItem
me={{
base: '16px',
md: '44px'
}}
>
<Link
fontWeight="500"
fontSize={{ base: '10px', md: 'sm' }}
color={textColor}
isExternal
href="https://horizon-ui.notion.site/Privacy-Policy-8addde50aa8e408ca5c5f5811c38f971"
>
Privacy Policy
</Link>
</ListItem>
<ListItem>
<Link
fontWeight="500"
fontSize={{ base: '10px', md: 'sm' }}
color={textColor}
isExternal
href="https://horizon-ui.notion.site/Refund-Policy-5d5fa25f7fac4978a0be6fcf3036c6ee"
>
Refund Policy
</Link>
</ListItem>
</List>
</Flex>
);
}

View File

@@ -1,158 +0,0 @@
/*eslint-disable*/
'use client';
import logo from '/public/logo-horizon-boilerplate.png';
import { HSeparator } from '@/components/separator/Separator';
import { Flex, Link, Text, Image, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
export function FooterWebsite() {
const textColorSecondary = useColorModeValue('gray.600', 'white');
return (
<Flex
zIndex="3"
flexDirection={{
base: 'column',
}}
alignItems="center"
justifyContent="space-between"
position="relative"
px={{ base: '20px', xl: '0px' }}
pb="50px"
bg="white"
>
<HSeparator
mb="0px"
mt={{ base: '0px', md: '100px', lg: '0px' }}
maxW="1170px"
mx="auto"
bg="gray.200"
/>
<Flex
justifyContent="space-between"
mt="50px"
w={{ base: '100%', xl: '1170px' }}
flexDirection={{
base: 'column',
lg: 'row',
}}
maxW={{ base: '100%', xl: '1170px' }}
maxH="max-content"
mx="auto"
>
<Link
display={'flex'}
alignItems="center"
justifyContent={'center'}
href="/"
>
<Image
alt=" "
w="36px"
src={logo.src}
/>
<Text ms="8px" me="10px" fontWeight="800" color="#120F43">
Horizon UI Boilerplate
</Text>
</Link>
<Flex
direction={{ base: 'column', md: 'row' }}
justifyItems="center"
alignItems="center"
textAlign={'center'}
w={{ base: '100%', md: '100%', lg: '100%', xl: 'unset' }}
>
<Flex
direction="column"
justify={'center'}
mx="auto"
align="center"
mb={{ base: '20px', lg: '0px' }}
>
<Flex my="auto" direction={{ base: 'column', md: 'row' }}>
<Link
isExternal={true}
href="/pricing"
fontSize="sm"
color={textColorSecondary}
fontWeight="500"
letterSpacing="0px"
me={{ base: '0px', md: '40px' }}
mb={{ base: '20px', md: '0px' }}
>
Pricing
</Link>
<Link
isExternal={true}
href="/dashboard/settings"
fontSize="sm"
color={textColorSecondary}
fontWeight="500"
letterSpacing="0px"
me={{ base: '0px', md: '40px' }}
mb={{ base: '20px', md: '0px' }}
>
Account
</Link>
<Link
isExternal={true}
href="https://horizon-ui.notion.site/Refund-Policy-5d5fa25f7fac4978a0be6fcf3036c6ee"
fontSize="sm"
color={textColorSecondary}
fontWeight="500"
letterSpacing="0px"
me={{ base: '0px', md: '40px' }}
mb={{ base: '20px', md: '0px' }}
>
Refund Policy
</Link>
<Link
isExternal={true}
href="https://horizon-ui.notion.site/Privacy-Policy-8addde50aa8e408ca5c5f5811c38f971"
fontSize="sm"
color={textColorSecondary}
fontWeight="500"
letterSpacing="0px"
me={{ base: '0px', md: '40px' }}
mb={{ base: '20px', md: '0px' }}
>
Privacy Policy
</Link>
<Link
isExternal={true}
href="https://horizon-ui.notion.site/Terms-Conditions-6e79229d25ed48f48a481962bc6de3ee"
fontSize="sm"
color={textColorSecondary}
fontWeight="500"
letterSpacing="0px"
me={{ base: '0px', md: '40px' }}
mb={{ base: '20px', md: '0px' }}
>
Terms of service
</Link>
</Flex>
</Flex>
</Flex>
</Flex>
<Flex w="100%" maxW="1170px" px={{ base: '10px', md: '100px' }}>
<Text
lineHeight="180%"
fontSize="sm"
textAlign="center"
color="gray.600"
fontWeight="500"
letterSpacing="0px"
mt="40px"
mb="40px"
>
<Text as="span" fontWeight={'700'}>
Use it with caution:
</Text>{' '}
This tool can be helpful, but it is not a substitute for your own
knowledge and understanding. Make sure to use it as a supplement to
your own research and writing, rather than relying on it exclusively.
</Text>
</Flex>
</Flex>
);
}

View File

@@ -1,22 +0,0 @@
import { createIcon } from '@chakra-ui/icons';
export const HeroBg = createIcon({
displayName: 'HeroBg',
viewBox: '0 0 1618 900',
path: (
<g
width="1618"
height="900"
viewBox="0 0 1618 900"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M101.583 301.413C94.4517 259.209 122.883 219.215 165.087 212.083L1382.96 6.28832C1472.87 -8.9049 1512.05 115.615 1429.63 154.64L642.704 527.238L1520.96 365.296C1607.06 349.42 1650.61 465.12 1575.37 509.938L942.158 887.084C905.385 908.987 857.818 896.932 835.916 860.158C814.013 823.385 826.068 775.818 862.842 753.916L1129.5 595.09L95.0792 785.827C4.69665 802.492 -35.766 676.987 47.2513 637.679L863.283 251.3L190.913 364.917C148.709 372.048 108.715 343.617 101.583 301.413Z"
fill="#E9E3FF"
/>
</g>
)
});

View File

@@ -1,42 +0,0 @@
'use client';
import { Image } from './Image';
import { chakra, useColorMode } from '@chakra-ui/system';
import { ComponentProps } from 'react';
type AvatarImageProps = Partial<
ComponentProps<typeof Image> & {
showBorder?: boolean;
}
>;
export function NextAvatar({
src,
showBorder,
alt = '',
style,
...props
}: AvatarImageProps) {
const { colorMode } = useColorMode();
return (
<Image
{...props}
{...(showBorder
? {
border: '2px',
borderColor: colorMode === 'dark' ? '#120F43' : 'white',
}
: {})}
alt={alt}
objectFit={'fill'}
src={src}
style={{ ...style, borderRadius: '50%' }}
/>
);
}
export const ChakraNextAvatar = chakra(NextAvatar, {
shouldForwardProp: (prop) =>
['width', 'height', 'src', 'alt', 'layout'].includes(prop),
});

View File

@@ -1,38 +0,0 @@
'use client'
import { Box, BoxProps } from '@chakra-ui/react';
import NextImage, { ImageProps } from 'next/legacy/image';
import { ComponentProps } from 'react';
type ChakraNextImageProps = Partial<ImageProps> &
Partial<BoxProps> & {
nextProps?: Partial<ComponentProps<typeof NextImage>>;
};
function parseAssetPrefix(image: string) {
const alreadyHasHttp = image.match('http');
if (alreadyHasHttp) return image;
const prefix = process.env.NEXT_PUBLIC_BASE_PATH || '';
const alreadyHasPrefix = image.match(prefix);
const finalUrl = alreadyHasPrefix ? image : `${prefix}${image}`;
return finalUrl;
}
export function Image(props: ChakraNextImageProps) {
const { src, alt, nextProps = {}, ...rest } = props;
const imageUrl =
typeof src === 'string' ? src : ((src as any)?.src as string);
return (
<Box overflow={'hidden'} position="relative" {...rest}>
<NextImage
layout="fill"
objectFit="fill"
src={parseAssetPrefix(imageUrl)}
alt={alt}
{...nextProps}
/>
</Box>
);
}

View File

@@ -1,371 +0,0 @@
/*eslint-disable*/
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Flex,
Text,
Box,
SimpleGrid,
useColorModeValue,
} from '@chakra-ui/react';
import Link from 'next/link';
export default function Home() {
const textColor = useColorModeValue('#120F43', 'white');
return (
<Box
w="100%"
pt={{ base: '90', md: '100px', xl: '140px' }}
bg="linear-gradient(180deg, #F8FAFC 0%, rgba(255, 255, 255, 0) 47.33%)"
id="faqs"
bgSize="cover"
>
<Flex
direction="column"
mx="auto"
mb="40px"
maxW={{ base: '90%', lg: '62%' }}
justify="center"
textAlign="center"
>
<Text
as="h3"
textAlign={{ base: 'center', lg: 'center' }}
fontWeight="700"
letterSpacing="2px"
color="brand.500"
fontSize={{ base: 'xs', md: 'md' }}
w="100%"
mb="10px"
>
FREQUENTLY ASKED QUESTIONS
</Text>
<Text
as="h2"
mx="auto"
color={textColor}
fontWeight="800"
fontSize={{ base: '30px', md: '38px', lg: '38px', xl: '38px' }}
lineHeight={{ base: '38px', md: '50px', lg: '50px', xl: '50px' }}
mb={{ base: '10px', md: '20px' }}
>
Frequently asked questions
</Text>
<Text
mx="auto"
color="gray.600"
fontSize={{ base: 'md', md: 'md', xl: 'lg' }}
fontWeight="500"
letterSpacing="0px"
lineHeight={{ base: '24px', md: '30px' }}
mb="30px"
maxW={{ base: '100%', md: '80%', lg: '60%' }}
>
Looking for something else? Chat with us via{' '}
<Link href="mailto:hello@horizon-ui.com ">hello@horizon-ui.com</Link>{' '}
and we will try our best to help you with your questions!
</Text>
</Flex>
<Box
w="100%"
maxW={{ base: '100%', md: '80%', lg: '860px' }}
mx="auto"
mb="120px"
>
<Accordion allowMultiple>
<AccordionItem borderTop="0px solid">
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
What is Horizon UI Boilerplate?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
Is Horizon UI Boilerplate Free?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
You can learn more on our{' '}
<Link href="/pricing">
<Text as="span" fontWeight={'bold'} color="brand.500">
Pricing Page.
</Text>
</Link>{' '}
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
How does Horizon UI Boilerplate work?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
How can I use Horizon UI Boilerplate?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
Is Horizon UI Boilerplate suitable for all academic levels?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
Can I trust the quality of the essays generated by Essay
Builder AI?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<Text>
<AccordionButton
py="25px"
_hover={{ bg: 'none' }}
fontSize="md"
letterSpacing="0px"
fontWeight={'700'}
color={textColor}
_active={{ boxShadow: 'none' }}
_focus={{ boxShadow: 'none' }}
>
<Flex as="h3" flex={1} textAlign="left">
Is the content generated by Horizon UI Boilerplate plagiarism-free?
</Flex>
<AccordionIcon />
</AccordionButton>
</Text>
<AccordionPanel pb={4}>
<SimpleGrid gap="40px" columns={1}>
<Text
color="gray.600"
fontWeight={'500'}
fontSize="md"
letterSpacing="0px"
>
This is an awesome example of how you can use our accordion
component for your FAQs section to provide clear, concise
answers while maintaining a clean and engaging user interface.
The intuitive design allows users to easily navigate through
common questions, expanding each section to find detailed
information without overwhelming them with text. It's an ideal
way to streamline your website's content and enhance user
experience, ensuring that visitors have quick access to the
answers they need.
</Text>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Box>
</Box>
);
}

View File

@@ -1,133 +0,0 @@
import InnerContent from '@/components/layout/innerContent';
import image from '@/public/img/features/feature-one.png';
import {
Flex,
Link,
Button,
Icon,
Image,
Text,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import { MdChevronRight } from 'react-icons/md';
export default function FeatureOne() {
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = useColorModeValue('gray.600', 'white');
return (
<Flex
w="100%"
direction={{ base: 'column' }}
pt={{ base: '100px', md: '140px', lg: '140px' }}
pb={{ base: '100px', md: '140px', lg: '140px' }}
overflow="hidden"
bgSize="cover"
position="relative"
>
<InnerContent px={{ base: '20px', md: '40px', xl: '0px' }}>
<Flex
align={'center'}
direction={{ base: 'column', lg: 'row' }}
maxW="100%"
justifyContent="space-between"
columnGap="50px"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Flex
direction="column"
my="auto"
maxW="100%"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Text
as="h3"
fontWeight="700"
letterSpacing="2px"
bg="brand.500"
bgClip="text"
fontSize={{ base: 'xs', md: 'md' }}
textAlign={{ base: 'center', lg: 'left' }}
w="100%"
mb="10px"
>
YOUR STARTUP FEATURES
</Text>
<Text
as="h2"
fontWeight="800"
color={textColor}
fontSize={{ base: '30px', md: '40px', xl: '42px' }}
lineHeight={{ base: '40px', md: '50px', lg: '52px' }}
mb="20px"
w={{ base: '100%', md: '80%', lg: '100%' }}
textAlign={{ base: 'center', lg: 'left' }}
maxW={{ base: '100%', md: 'unset' }}
>
Ready to use Web App
<br />
for your Startup project
</Text>
<Text
color={textColorSecondary}
textAlign={{ base: 'center', lg: 'left' }}
fontSize={{ base: 'sm', md: 'md', xl: 'md' }}
w={{ base: '94%', md: '94%', lg: '97%' }}
lineHeight={{ base: '24px', md: '30px' }}
fontWeight="500"
letterSpacing="0px"
mb="30px"
>
Its so easy to beat your endless procrastination when you have
all the necessary resources to get that project done and start to
generate your startups first dollar in just a few days.
</Text>
<Flex
align="center"
direction={{ base: 'column', md: 'row' }}
mb={{ md: '0px', lg: '30px' }}
justifyContent={{ base: 'center', lg: 'unset' }}
>
<Link href="/dashboard/signin" me={{ base: '0px', md: '14px' }}>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '230px' }}
h="54px"
>
Get started now
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
<Link href="/dashboard/signin">
<Button
py="20px"
px="16px"
fontSize="sm"
variant="setup"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '160px' }}
h="54px"
>
Try it for Free
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
</Flex>
</Flex>
<Image
alt=" "
src={image.src}
w={{ base: '100%', lg: '415px', xl: '575px' }}
mt={{ base: '20px', md: '50px', lg: '0px' }}
/>
</Flex>
</InnerContent>
</Flex>
);
}

View File

@@ -1,130 +0,0 @@
import InnerContent from '@/components/layout/innerContent';
import image from '@/public/img/features/feature-three.png';
import {
Flex,
Link,
Button,
Icon,
Image,
Text,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import { MdChevronRight } from 'react-icons/md';
export default function FeatureOne() {
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = useColorModeValue('gray.600', 'white');
return (
<Flex
w="100%"
direction={{ base: 'column' }}
pb={{ base: '100px', md: '140px', lg: '140px' }}
overflow="hidden"
bgSize="cover"
position="relative"
>
<InnerContent px={{ base: '20px', md: '40px', xl: '0px' }}>
<Flex
align={'center'}
direction={{ base: 'column', lg: 'row' }}
maxW="100%"
justifyContent="space-between"
columnGap="50px"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Flex
direction="column"
my="auto"
maxW="100%"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Text
as="h3"
fontWeight="700"
letterSpacing="2px"
bg="linear-gradient(89deg, #3D1DFF 9.03%, #6147FF 10.23%, #D451FF 20.91%, #EC458D 30.02%, #FFCA8B 44.68%)"
bgClip="text"
fontSize={{ base: 'xs', md: 'md' }}
textAlign={{ base: 'center', lg: 'left' }}
w="100%"
mb="10px"
>
DISCOVER MORE WITH PRO
</Text>
<Text
as="h2"
fontWeight="800"
color={textColor}
fontSize={{ base: '26px', md: '40px', xl: '42px' }}
lineHeight={{ base: '36px', md: '50px', lg: '52px' }}
mb="20px"
w={{ base: '100%', md: '80%', lg: '100%' }}
textAlign={{ base: 'center', lg: 'left' }}
maxW={{ base: '100%', md: 'unset' }}
>
Generate an Outstanding SaaS without limitations
</Text>
<Text
color={textColorSecondary}
textAlign={{ base: 'center', lg: 'left' }}
fontSize={{ base: 'sm', md: 'md', xl: 'md' }}
w={{ base: '100%', md: '80%', lg: '97%' }}
lineHeight={{ base: '24px', md: '30px' }}
fontWeight="500"
letterSpacing="0px"
mb="30px"
>
Give life to your startup project by choosing from a premium pack
of top-notch landing sections like Hero, Features, Call to
Actions, Pricing, Navigations, Auth pages, Dashboard, and so on.
</Text>
<Flex
align="center"
direction={{ base: 'column', md: 'row' }}
mb={{ md: '0px', lg: '30px' }}
justifyContent={{ base: 'center', lg: 'unset' }}
>
<Link href="/pricing" me={{ base: '0px', md: '14px' }}>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '210px' }}
h="54px"
>
Get started with PRO
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
<Link href="/pricing">
<Button
py="20px"
px="16px"
fontSize="sm"
variant="setup"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '190px' }}
h="54px"
>
See pricing Plans
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
</Flex>
</Flex>
<Image
alt=" "
src={image.src}
w={{ base: '100%', lg: '415px', xl: '575px' }}
mt={{ base: '20px', md: '50px', lg: '0px' }}
/>
</Flex>
</InnerContent>
</Flex>
);
}

View File

@@ -1,129 +0,0 @@
import InnerContent from '@/components/layout/innerContent';
import image from '@/public/img/features/feature-two.png';
import {
Flex,
Link,
Button,
Icon,
Image,
Text,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import { MdChevronRight } from 'react-icons/md';
export default function FeatureOne() {
const textColor = useColorModeValue('#120F43', 'white');
const textColorSecondary = useColorModeValue('gray.600', 'white');
return (
<Flex
w="100%"
direction={{ base: 'column' }}
pb={{ base: '100px', md: '140px', lg: '140px' }}
overflow="hidden"
bgSize="cover"
position="relative"
>
<InnerContent px={{ base: '20px', md: '40px', xl: '0px' }}>
<Flex
align={'center'}
direction={{ base: 'column-reverse', lg: 'row' }}
maxW="100%"
justifyContent="space-between"
columnGap="90px"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Image
alt=" "
src={image.src}
w={{ base: '100%', lg: '415px', xl: '575px' }}
mt={{ base: '20px', md: '50px', lg: '0px' }}
/>
<Flex
direction="column"
my="auto"
maxW="100%"
alignItems={{ base: 'center', lg: 'unset' }}
>
<Text
as="h3"
fontWeight="700"
letterSpacing="2px"
bg="linear-gradient(89deg, #3D1DFF 9.03%, #6147FF 10.23%, #D451FF 20.91%, #EC458D 30.02%, #FFCA8B 44.68%)"
bgClip="text"
fontSize={{ base: 'xs', md: 'md' }}
textAlign={{ base: 'center', lg: 'left' }}
mb="10px"
>
EXCLUSIVE PRO FEATURE
</Text>
<Text
as="h2"
fontWeight="800"
color={textColor}
fontSize={{ base: '30px', md: '40px', xl: '42px' }}
lineHeight={{ base: '40px', md: '50px', lg: '52px' }}
mb="20px"
w={{ base: '100%', md: '70%', lg: '100%' }}
textAlign={{ base: 'center', lg: 'left' }}
maxW={{ base: '100%', md: 'unset' }}
>
Advanced Platform for your Startup Web App
</Text>
<Text
color={textColorSecondary}
textAlign={{ base: 'center', lg: 'left' }}
fontSize={{ base: 'sm', md: 'md', xl: 'md' }}
w={{ base: '100%', md: '80%', lg: '100%' }}
lineHeight={{ base: '24px', md: '30px' }}
fontWeight="500"
letterSpacing="0px"
mb="30px"
>
Horizon UI Boilerplate comes with a premium pack that includes all
the necessary resources to launch your startup, like the fully
coded web app pages, landing, database, payments and so on.
</Text>
<Flex
align="center"
direction={{ base: 'column', md: 'row' }}
mb={{ md: '0px', lg: '30px' }}
justifyContent={{ base: 'center', lg: 'unset' }}
>
<Link href="/pricing" me={{ base: '0px', md: '14px' }}>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '210px' }}
h="54px"
>
Get started now
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
<Link href="/pricing">
<Button
py="20px"
px="16px"
fontSize="sm"
variant="setup"
borderRadius="45px"
mb={{ base: '20px', md: '0px' }}
w={{ base: '335px', md: '190px' }}
h="54px"
>
Try it for Free
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
</Flex>
</Flex>
</Flex>
</InnerContent>
</Flex>
);
}

View File

@@ -1,294 +0,0 @@
import { HeroBg } from '@/components/icons/HeroBg';
import dashboard from '@/public/img/first-section/dashboard-world-greatest-section.png';
import left from '@/public/img/first-section/left-image-worlds-greatest.png';
import right from '@/public/img/first-section/right-image-worlds-greatest.png';
import nextjs from '@/public/img/hero/nextjs.png';
import openai from '@/public/img/hero/openai.png';
import stripe from '@/public/img/hero/stripe.png';
import supabase from '@/public/img/hero/supabase.png';
import chakra from '@/public/img/hero/chakra.png';
import userauth from '@/public/img/hero/user-auth.png';
import {
Box,
Icon,
Flex,
Image,
Text,
useColorModeValue,
SimpleGrid,
} from '@chakra-ui/react';
import React from 'react';
export default function FirstSection() {
const brandColorPrice = useColorModeValue('brand.500', 'white');
const textColor = useColorModeValue('#120F43', 'white');
return (
<Flex
zIndex="2"
w="100%"
direction={{ base: 'column' }}
bgSize="cover"
position="relative"
pt={{ base: '90px', md: '100px', xl: '100px' }}
>
<SimpleGrid
columns={{ base: 1, md: 3, xl: 6 }}
w="100%"
gap="16px"
maxW="1170px"
mx="auto"
mb="86px"
>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={nextjs.src}
w="60px"
h="60px"
alt="nextjs logo"
/>
<Text fontWeight="bold" color={textColor}>
NextJS 14
</Text>
</Flex>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={stripe.src}
w="60px"
h="60px"
alt="stripe logo"
/>
<Text fontWeight="bold" color={textColor}>
Stripe
</Text>
</Flex>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={supabase.src}
w="60px"
h="60px"
alt="supabase logo"
/>
<Text fontWeight="bold" color={textColor}>
Supabase
</Text>
</Flex>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={chakra.src}
w="60px"
h="60px"
alt="chakra ui logo"
/>
<Text fontWeight="bold" color={textColor}>
Chakra UI
</Text>
</Flex>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={openai.src}
w="60px"
h="60px"
alt="openai logo"
/>
<Text fontWeight="bold" color={textColor}>
AI Integration
</Text>
</Flex>
<Flex
direction="column"
align="center"
justify="center"
border="1px solid"
borderColor="secondaryGray.400"
borderRadius="14px"
py="39px"
>
<Image
borderRadius="12px"
mb="20px"
src={userauth.src}
w="60px"
h="60px"
alt="auth0 logo"
/>
<Text fontWeight="bold" color={textColor}>
User Auth
</Text>
</Flex>
</SimpleGrid>
<Flex
direction="column"
px={{ base: '20px', md: '40px', xl: '0px' }}
maxW="unset"
>
<Flex direction="column" width="stretch">
<Flex
direction="column"
mx="auto"
alignItems="center"
textAlign="center"
>
<Text
as="h3"
textAlign={{ base: 'center', lg: 'center' }}
fontWeight="700"
letterSpacing="2px"
color={brandColorPrice}
fontSize={{ base: 'xs', md: 'md' }}
w="100%"
mb="10px"
>
BEST AI NEXTJS BOILERPLATE
</Text>
<Text
as="h2"
textAlign={{ base: 'center' }}
color={textColor}
fontWeight="800"
fontSize={{ base: '30px', md: '48px', lg: '48px', xl: '58px' }}
lineHeight={{ base: '38px', md: '60px', lg: '60px', xl: '70px' }}
mb={{ base: '20px', md: '30px' }}
w={{ base: '100%', md: '80%', lg: '60%', xl: '50%' }}
mx="auto"
>
Your All-in-One <br />
Startup Boilerplate
</Text>
<Text
color="gray.600"
fontSize={{ base: 'sm', md: 'md', xl: 'lg' }}
fontWeight="500"
letterSpacing="0px"
lineHeight={{ base: '24px', md: '30px' }}
w={{
base: '100%',
md: '80%',
lg: '80%',
xl: '56%',
'2xl': '54%',
}}
>
Tap into the power of Artificial Intelligence for your startup
needs with Horizon UI Boilerplate, the most complex NextJS
boilerplate to launch your web app project in just a few moments.
</Text>
</Flex>
</Flex>
<Flex
position={'relative'}
justifyContent="center"
mt={{ base: '16px', md: '10px', lg: '40px' }}
maxW={{ base: '335px', md: '1170px' }}
mx="auto"
>
<Icon
as={HeroBg}
position="absolute"
mx="auto"
w={{
base: '500px',
md: '750px',
lg: '1000px',
xl: '1800px',
}}
h={{
base: '500px',
md: '750px',
lg: '1000px',
xl: '820px',
}}
left="50%"
transform="translate(-50%,0px)"
top={{
base: '-130px',
md: '-90px',
lg: '-100px',
xl: '-80px',
}}
/>
<Image
src={dashboard.src}
zIndex={'1'}
alt=""
maxH="max-content"
w="100%"
maxW={{ base: '335px', md: '1170px' }}
borderRadius="8px"
boxShadow="0px 26.83487px 155.64224px -46.15597px #CBD5E0"
/>
<Image
zIndex={'1'}
src={left.src}
alt=""
position={'absolute'}
w={{ base: '62px', md: '122px', xl: '224px' }}
left={{ base: '1px', md: '5px', lg: '10px', xl: '-20px' }}
top={{ base: '33px', md: '75px', lg: '36px', xl: '45px' }}
boxShadow="0px 10.1683px 61.0098px rgba(0, 0, 0, 0.05)"
borderRadius="8px"
/>
<Image
src={right.src}
alt=""
position="absolute"
right={{ base: '-16px', md: '-30px', lg: '-80px', xl: '-53px' }}
top={{ base: '48px', md: '105px', lg: '44px', xl: '98px' }}
w={{ base: '286px', md: '592px', lg: '806px', xl: '1026px' }}
borderRadius="8px"
zIndex={'1'}
/>
</Flex>
</Flex>
</Flex>
);
}

View File

@@ -1,183 +0,0 @@
import imageLeft from '@/public/img/hero/left-image.png';
import imageRight from '@/public/img/hero/right-image.png';
import { Button, Image, Icon, Flex, Link, Text } from '@chakra-ui/react';
import React from 'react';
import { IoIosStar } from 'react-icons/io';
import { MdChevronRight } from 'react-icons/md';
export default function hero() {
return (
<Flex
mx="auto"
mt={{ base: '90px', lg: '114px' }}
w="96vw"
h={{
base: '560px',
md: '580px',
lg: '580px',
xl: '620px',
'2xl': '84vh',
}}
overflow="hidden"
alignItems="center"
alignContent="center"
position={'relative'}
maxW="100%"
direction={{ base: 'column' }}
bg="var(--linear-3, radial-gradient(98.96% 75.83% at 50% 0%, #948FE8 0%, #363285 22.92%, #110D5B 42.71%, #050327 88.54%))"
borderRadius={{ base: '20px', md: '30px' }}
>
<Flex h="100%" w="100%">
<Flex
maxW="100%"
h="100%"
direction="row"
width="stretch"
justifyContent="space-between"
alignItems="center"
alignContent="center"
mb={{ base: '0px', md: '30px' }}
>
<Image
position="absolute"
left="0"
display={{ base: 'none', xl: 'unset' }}
src={imageLeft.src}
alt=" "
w={{ base: '90%', md: '100%', lg: '30%', xl: '30%' }}
/>
<Flex direction="column" mx="auto" textAlign="center">
<Text
as="h1"
color="white"
zIndex="100"
fontSize={{
base: '32px',
md: '44px',
lg: '44px',
xl: '44px',
'2xl': '58px',
}}
lineHeight={{
base: '40px',
md: '54px',
lg: '54px',
xl: '54px',
'2xl': '68px',
}}
w={{
base: '90%',
md: '80%',
lg: '60%',
xl: '50%',
'2xl': '50%',
'3xl': '50%',
}}
alignSelf="center"
mb={{ base: '16px', md: '20px' }}
fontWeight="700"
>
Launch your startup project 10X faster in a few moments
</Text>
<Text
as="p"
mb={{ base: '30px', md: '30px' }}
color={'white'}
alignSelf="center"
fontSize={{ base: 'sm', md: 'md', '2xl': 'md' }}
lineHeight={{ base: '24px', md: '30px' }}
letterSpacing="0px"
fontWeight="500"
w={{
base: '91%',
md: '82%',
lg: '62%',
xl: '44%',
'2xl': '41%',
'3xl': '41%',
}}
>
Create a professional website for your startup in no time with
Horizon UI Boilerplate. Our comprehensive template will help you
launch your project 10X faster, leaving you more time to focus on
your business.
</Text>
<Link
w={{ base: '300px', md: '340px' }}
alignSelf="center"
href="/dashboard/signin"
>
<Button
variant="primary"
py="24px"
bg="linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important"
px="24px"
fontSize="md"
borderRadius="45px"
w={{ base: '300px', md: '340px' }}
h="70px"
>
Go to dashboard
<Icon
as={MdChevronRight}
color="white"
mt="4px"
ms="2px"
h="16px"
w="16px"
/>
</Button>
</Link>
<Flex
align="center"
direction="column"
justifyContent={{ base: 'center', lg: 'center' }}
>
{' '}
<Text
as="h3"
mt={{ base: '20px', md: '20px' }}
mb="10px"
color="white"
alignSelf="center"
fontSize="md"
letterSpacing="0px"
fontWeight={'500'}
>
Used by 80,000+ users monthly
</Text>
<Flex
justify={{ base: 'center', md: 'start' }}
alignItems="center"
>
<Icon as={IoIosStar} w="22px" h="22px" color="#F6AD55" />
<Icon as={IoIosStar} w="22px" h="22px" color="#F6AD55" />
<Icon as={IoIosStar} w="22px" h="22px" color="#F6AD55" />
<Icon as={IoIosStar} w="22px" h="22px" color="#F6AD55" />
<Icon
as={IoIosStar}
w="22px"
h="22px"
color="orange.300"
me="8px"
/>
<Text color="white" mt="2px" fontWeight="bold" fontSize="lg">
4.9
</Text>
</Flex>
</Flex>
</Flex>
<Image
position="absolute"
right="0"
display={{ base: 'none', xl: 'unset' }}
src={imageRight.src}
alt=" "
w={{ base: '90%', md: '100%', lg: '30%', xl: '30%' }}
/>
</Flex>
</Flex>
</Flex>
);
}

View File

@@ -1,141 +0,0 @@
/*eslint-disable*/
'use client';
import { FooterWebsite } from '@/components/footer/FooterWebsite';
import Faq from '@/components/landing/faq';
import FeatureOne from '@/components/landing/feature-one';
import FeatureThree from '@/components/landing/feature-three';
import FeatureTwo from '@/components/landing/feature-two';
import FirstSection from '@/components/landing/first-section';
import Hero from '@/components/landing/hero';
import SecondSection from '@/components/landing/second-section';
import NavbarFixed from '@/components/navbar/NavbarFixed';
import { Database } from '@/types_db';
import { Button, Flex, Input, Text } from '@chakra-ui/react';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
export default function Home() {
return (
<>
<NavbarFixed />
<Flex
direction="column"
align="center"
h="100%"
minH="100vh"
overflow="hidden"
position="relative"
>
<Flex
w="100%"
direction="column"
pb={{ base: '0px', md: '80px', lg: '80px', xl: '80px' }}
position="relative"
justifyContent="center"
alignItems="center"
>
<Hero />
<FirstSection />
<SecondSection />
<FeatureOne />
<FeatureTwo />
<FeatureThree />
<Faq />
<Flex
direction={'column'}
maxW="100%"
mx="auto"
mb={{ base: '60px', md: '60px' }}
>
<Text
color="navy.700"
fontWeight={'800'}
fontSize="30px"
mb="20px"
textAlign={'center'}
>
Join our newsletter
</Text>
<Text
fontWeight={'500'}
fontSize={{ base: '15px', md: 'lg' }}
color="gray.600"
px={{ base: '10px', md: '0px' }}
mb="30px"
textAlign={'center'}
>
By subscribing, you'll be the first to know about the latest news
and updates.
</Text>
<form
id="form-fbcaaaec-e795-4419-b112-06934fd0051d"
action="https://api.encharge.io/v1/forms/fbcaaaec-e795-4419-b112-06934fd0051d/submission/plain"
method="POST"
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexWrap: 'wrap'
}}
>
<div className="sc-jzJRlG kfekry">
<div className="encharge-form-group sc-jTzLTM frRvjZ form-group">
<Input
variant="main"
placeholder="Enter your email*"
me="14px"
h="100%"
isRequired={true}
w={{ base: '96%', md: '420px' }}
maxW="100%"
fontWeight="500"
_placeholder={{
color: 'gray.600',
fontWeight: '500'
}}
borderRadius="70px"
mb="0px !important"
type="email"
id="31b6ea2a-d9c7-4b42-9a01-7677838f07e9"
name="email"
className="encharge-form-input sc-kAzzGY kTMZCx form-control"
/>
</div>
</div>
<div className="sc-cSHVUG ebRkVm">
<Button
py="20px"
px="40px"
fontSize="sm"
fontWeight={'600'}
variant="primary"
borderRadius="45px"
bg="linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important"
w={{ base: '100%', md: '150px' }}
h="58px"
type="submit"
className="encharge-form-submit-button sc-gZMcBi ejYzxT btn btn-primary"
>
Subscribe
</Button>
</div>
</form>
</Flex>
</Flex>
<FooterWebsite />
</Flex>
</>
);
}

View File

@@ -1,187 +0,0 @@
// eslint-disabled
import { Icon, Flex, Text, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import { MdChevronRight } from 'react-icons/md';
export default function SecondSection() {
const brandColorPrice = useColorModeValue('brand.500', 'white');
const textColor = useColorModeValue('#120F43', 'white');
return (
<Flex
id="features"
zIndex="2"
w="100%"
direction={{ base: 'column' }}
bgSize="cover"
alignItems="center"
position="relative"
pt={{ base: '90px', md: '100px', xl: '140px' }}
>
<Flex
direction="column"
px={{ base: '0px', md: '40px', xl: '0px' }}
maxW="1170px"
justifyContent="center"
alignItems="center"
>
<Flex direction="column" width="stretch">
<Flex
direction="column"
mx="auto"
alignItems="center"
textAlign="center"
>
<Text
as="h3"
textAlign={{ base: 'center', lg: 'center' }}
fontWeight="700"
letterSpacing="2px"
color={brandColorPrice}
fontSize={{ base: 'xs', md: 'md' }}
w="100%"
mb="10px"
>
HOW IT WORKS
</Text>
<Text
as="h2"
textAlign={{ base: 'center' }}
color={textColor}
fontWeight="800"
fontSize={{ base: '30px', md: '48px', lg: '48px', xl: '58px' }}
lineHeight={{ base: '38px', md: '60px', lg: '60px', xl: '70px' }}
mb={{ base: '20px', md: '30px' }}
mx="auto"
>
How it works?
</Text>
</Flex>
</Flex>
<Flex
w={{ base: '86%', md: '76%', lg: '100%' }}
pt={{ base: '40px', md: '60px', xl: '60px' }}
maxW="100%"
flexDirection={{ base: 'column', lg: 'row' }}
align={'center'}
justify="center"
>
<Flex
direction="column"
me={{ base: '0px', lg: '32px' }}
mb={{ base: '50px', lg: '0px' }}
>
<Text
as="h3"
color="navy.700"
fontWeight={'800'}
textAlign={{ base: 'center', md: 'left' }}
fontSize="20px"
mb="12px"
>
Step 1: This is an example
</Text>
<Text
color="gray.600"
fontWeight={'500'}
fontSize={{ base: '15px', md: 'md' }}
textAlign={{ base: 'center', md: 'left' }}
lineHeight={{ base: '28px', md: '30px' }}
w="98%"
>
This is where your first step paragraph goes. For the moment, this
is just an example to see what it will look like.
</Text>
</Flex>
<Flex
justify="center"
align="center"
bg="white"
boxShadow={'0px 10.83px 28px -2px rgba(203, 213, 224, 0.79)'}
borderRadius="50px"
display={{ base: 'none', lg: 'flex' }}
me={{ base: '0px', lg: '32px' }}
minW="38px"
minH="38px"
>
<Icon
w="23px"
h="23px"
color="#7B5AFF"
bg="transparent"
as={MdChevronRight}
/>
</Flex>
<Flex
direction="column"
me={{ base: '0px', lg: '20px' }}
mb={{ base: '50px', lg: '0px' }}
>
<Text
as="h3"
color="navy.700"
fontWeight={'800'}
fontSize="20px"
mb="12px"
textAlign={{ base: 'center', md: 'left' }}
>
Step 2: This is another example
</Text>
<Text
color="gray.600"
fontWeight={'500'}
fontSize={{ base: '15px', md: 'md' }}
textAlign={{ base: 'center', md: 'left' }}
lineHeight={{ base: '28px', md: '30px' }}
w="98%"
>
This is where your second step paragraph goes. For the moment,
this is just an example to see what it will look like.
</Text>
</Flex>
<Flex
justify="center"
align="center"
bg="white"
boxShadow={'0px 10.83px 28px -2px rgba(203, 213, 224, 0.79)'}
borderRadius="50px"
display={{ base: 'none', lg: 'flex' }}
me={{ base: '0px', lg: '32px' }}
minW="38px"
minH="38px"
>
<Icon
w="23px"
h="23px"
color="#7B5AFF"
bg="transparent"
as={MdChevronRight}
/>
</Flex>
<Flex direction="column">
<Text
as="h3"
color="navy.700"
fontWeight={'800'}
fontSize="20px"
mb="12px"
textAlign={{ base: 'center', md: 'left' }}
>
Step 3: This is an example too
</Text>
<Text
color="gray.600"
fontWeight={'500'}
fontSize={{ base: '15px', md: 'md' }}
textAlign={{ base: 'center', md: 'left' }}
lineHeight={{ base: '28px', md: '30px' }}
>
This is where your third step paragraph goes. For the moment, this
is just an example to see what it will look like.
</Text>
</Flex>
</Flex>
</Flex>
</Flex>
);
}

View File

@@ -1,105 +0,0 @@
import Footer from '@/components/footer/FooterAdmin';
import Navbar from '@/components/navbar/NavbarAdmin';
import { routes } from '@/components/routes';
import Sidebar from '@/components/sidebar/Sidebar';
import { Database } from '@/types_db';
import { getActiveRoute } from '@/utils/navigation';
import { Box, useDisclosure } from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { usePathname } from 'next/navigation';
import {
PlanContext,
OpenContext,
ProductsContext,
SubscriptionContext,
UserContext,
UserDetailsContext,
ApiKeyContext
} from '@/contexts/layout';
import React from 'react';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
children: React.ReactNode;
title: string;
description: string;
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
userDetails: { [x: string]: any } | null;
}
const DashboardLayout: React.FC<Props> = (props: Props) => {
const pathname = usePathname();
const [open, setOpen] = React.useState(false);
const [plan, setPlan] = React.useState({
product: 'prod_QfhYC6AAtI5IKW',
price: 'price_1PoM9GDWNoHJSR0zmwpicH8y'
});
const [apiKey, setApiKey] = React.useState('default');
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<UserContext.Provider value={props.user}>
<UserDetailsContext.Provider value={props.user}>
<OpenContext.Provider value={{ open, setOpen }}>
<PlanContext.Provider value={{ plan, setPlan }}>
<ProductsContext.Provider value={props.products}>
<SubscriptionContext.Provider value={props.subscription}>
<ApiKeyContext.Provider value={{ apiKey, setApiKey }}>
<Box>
<Sidebar routes={routes} />
<Box
pt={{ base: '70px', md: '80px' }}
float="right"
minHeight="100vh"
height="100%"
overflow="auto"
position="relative"
maxHeight="100%"
w={{ base: '100%', xl: 'calc( 100% - 290px )' }}
maxWidth={{ base: '100%', xl: 'calc( 100% - 290px )' }}
transition="all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1)"
transitionDuration=".2s, .2s, .35s"
transitionProperty="top, bottom, width"
transitionTimingFunction="linear, linear, ease"
>
<Navbar
onOpen={onOpen}
logoText={'Horizon UI Boilerplate'}
userDetails={props.userDetails}
brandText={getActiveRoute(routes, pathname)}
/>
<Box
mx="auto"
p={{ base: '20px', md: '30px' }}
pe="20px"
minH="100vh"
>
{props.children}
</Box>
<Footer />
</Box>
</Box>
</ApiKeyContext.Provider>
</SubscriptionContext.Provider>
</ProductsContext.Provider>
</PlanContext.Provider>
</OpenContext.Provider>
</UserDetailsContext.Provider>
</UserContext.Provider>
);
};
export default DashboardLayout;

View File

@@ -1,17 +0,0 @@
import { Flex } from '@chakra-ui/react';
import React from 'react';
export default function InnerContent(props) {
const { children, ...rest } = props;
return (
<Flex
direction={{ base: 'column' }}
maxW={{ xl: '1170px' }}
align="center"
mx="auto"
{...rest}
>
{children}
</Flex>
);
}

View File

@@ -1,19 +0,0 @@
'use client';
import { ButtonProps } from '@chakra-ui/react';
import NextLink, { LinkProps as NextLinkProps } from 'next/link';
import { Button } from '@chakra-ui/react';
type LinkProps = ButtonProps & NextLinkProps;
function Link({ href, children, ...props }: LinkProps) {
return (
<NextLink href={href} passHref legacyBehavior>
<Button as="a" variant="a" {...props}>
{children}
</Button>
</NextLink>
);
}
export default Link;

View File

@@ -1,20 +0,0 @@
'use client';
import Link, { LinkProps } from 'next/link';
import { Button, ButtonProps } from '@chakra-ui/react';
type ChakraAndNextProps = ButtonProps & LinkProps;
export default function LinkButton({
href,
children,
prefetch = true,
...props
}: ChakraAndNextProps) {
return (
<Link href={href} passHref prefetch={prefetch}>
<Button as="a" variant="a" {...props}>
{children}
</Button>
</Link>
);
}

View File

@@ -1,31 +0,0 @@
'use client';
import NextLink, { LinkProps as NextLinkProps } from 'next/link';
import {
CSSProperties,
ComponentProps,
PropsWithChildren,
useMemo,
} from 'react';
export type NavLinkProps = NextLinkProps &
PropsWithChildren & {
styles?: CSSProperties;
borderRadius?: ComponentProps<typeof NextLink>['style'];
};
function NavLink({ children, styles, ...props }: NavLinkProps) {
const memoizedStyles = useMemo(
() => ({
...styles,
}),
[styles],
);
return (
<NextLink style={memoizedStyles} {...props}>
{children}
</NextLink>
);
}
export default NavLink;

View File

@@ -1,43 +0,0 @@
// chakra imports
import { Icon, Flex, Text, useColorModeValue } from '@chakra-ui/react';
import { MdUpgrade } from 'react-icons/md';
export function ItemContent(props: { info: string }) {
const textColor = useColorModeValue('navy.700', 'white');
return (
<>
<Flex
justify="center"
align="center"
borderRadius="16px"
minH={{ base: '60px', md: '70px' }}
h={{ base: '60px', md: '70px' }}
minW={{ base: '60px', md: '70px' }}
w={{ base: '60px', md: '70px' }}
me="14px"
bgGradient="linear(to-b, brand.400, brand.600)"
>
<Icon as={MdUpgrade} color="white" w={8} h={14} />
</Flex>
<Flex flexDirection="column">
<Text
mb="5px"
fontWeight="bold"
color={textColor}
fontSize={{ base: 'md', md: 'md' }}
>
New Update: {props.info}
</Text>
<Flex alignItems="center">
<Text
fontSize={{ base: 'sm', md: 'sm' }}
lineHeight="100%"
color={textColor}
>
A new update for your downloaded item is available!
</Text>
</Flex>
</Flex>
</>
);
}

View File

@@ -1,149 +0,0 @@
// Chakra imports
import {
Icon,
Flex,
Text,
Menu,
MenuButton,
MenuItem,
MenuList,
useDisclosure,
useColorModeValue
} from '@chakra-ui/react';
// Assets
import {
MdOutlineMoreHoriz,
MdOutlinePerson,
MdOutlineCardTravel,
MdOutlineLightbulb,
MdOutlineSettings
} from 'react-icons/md';
export default function Banner(props: { [x: string]: any }) {
const { ...rest } = props;
const textColor = useColorModeValue('secondaryGray.500', 'white');
const textHover = useColorModeValue(
{ color: '#120F43', bg: 'unset' },
{ color: 'secondaryGray.500', bg: 'unset' }
);
const iconColor = useColorModeValue('brand.500', 'white');
const bgList = useColorModeValue('white', 'whiteAlpha.100');
const bgShadow = useColorModeValue('14px 17px 40px 4px rgba(112, 144, 176, 0.08)', 'unset');
const bgButton = useColorModeValue('secondaryGray.300', 'whiteAlpha.100');
const bgHover = useColorModeValue({ bg: 'secondaryGray.400' }, { bg: 'whiteAlpha.50' });
const bgFocus = useColorModeValue({ bg: 'secondaryGray.300' }, { bg: 'whiteAlpha.100' });
// Ellipsis modals
const { isOpen: isOpen1, onOpen: onOpen1, onClose: onClose1 } = useDisclosure();
return (
<Menu isOpen={isOpen1} onClose={onClose1}>
<MenuButton
alignItems='center'
justifyContent='center'
bg={bgButton}
_hover={bgHover}
_focus={bgFocus}
_active={bgFocus}
w='37px'
h='37px'
lineHeight='100%'
onClick={onOpen1}
borderRadius='10px'
{...rest}>
<Icon as={MdOutlineMoreHoriz} color={iconColor} w='24px' h='24px' mt='4px' />
</MenuButton>
<MenuList
w='150px'
minW='unset'
maxW='150px !important'
border='transparent'
backdropFilter='blur(63px)'
bg={bgList}
boxShadow={bgShadow}
borderRadius='20px'
p='15px'>
<MenuItem
transition='0.2s linear'
color={textColor}
_hover={textHover}
p='0px'
borderRadius='8px'
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlinePerson} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 1
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
p='0px'
borderRadius='8px'
color={textColor}
_hover={textHover}
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlineCardTravel} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 2
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
p='0px'
borderRadius='8px'
color={textColor}
_hover={textHover}
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlineLightbulb} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 3
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
color={textColor}
_hover={textHover}
p='0px'
borderRadius='8px'
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}>
<Flex align='center'>
<Icon as={MdOutlineSettings} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 4
</Text>
</Flex>
</MenuItem>
</MenuList>
</Menu>
);
}

View File

@@ -1,128 +0,0 @@
// Chakra imports
import {
Menu,
MenuButton,
MenuItem,
MenuList,
useDisclosure,
useColorModeValue,
Flex,
Icon,
Text
} from '@chakra-ui/react';
// Assets
import { MdOutlinePerson, MdOutlineCardTravel, MdOutlineLightbulb, MdOutlineSettings } from 'react-icons/md';
export default function Banner(props: { icon: JSX.Element | string; [x: string]: any }) {
const { icon, ...rest } = props;
// Ellipsis modals
const { isOpen: isOpen1, onOpen: onOpen1, onClose: onClose1 } = useDisclosure();
// Chakra color mode
const textColor = useColorModeValue('secondaryGray.500', 'white');
const textHover = useColorModeValue(
{ color: '#120F43', bg: 'unset' },
{ color: 'secondaryGray.500', bg: 'unset' }
);
const bgList = useColorModeValue('white', 'whiteAlpha.100');
const bgShadow = useColorModeValue('14px 17px 40px 4px rgba(112, 144, 176, 0.08)', 'unset');
return (
<Menu isOpen={isOpen1} onClose={onClose1}>
<MenuButton {...rest} onClick={onOpen1}>
{icon}
</MenuButton>
<MenuList
w='150px'
minW='unset'
maxW='150px !important'
border='transparent'
backdropFilter='blur(63px)'
bg={bgList}
boxShadow={bgShadow}
borderRadius='20px'
p='15px'>
<MenuItem
transition='0.2s linear'
color={textColor}
_hover={textHover}
p='0px'
borderRadius='8px'
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlinePerson} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 1
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
p='0px'
borderRadius='8px'
color={textColor}
_hover={textHover}
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlineCardTravel} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 2
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
p='0px'
borderRadius='8px'
color={textColor}
_hover={textHover}
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}
mb='10px'>
<Flex align='center'>
<Icon as={MdOutlineLightbulb} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 3
</Text>
</Flex>
</MenuItem>
<MenuItem
transition='0.2s linear'
color={textColor}
_hover={textHover}
p='0px'
borderRadius='8px'
_active={{
bg: 'transparent'
}}
_focus={{
bg: 'transparent'
}}>
<Flex align='center'>
<Icon as={MdOutlineSettings} h='16px' w='16px' me='8px' />
<Text fontSize='sm' fontWeight='400'>
Panel 4
</Text>
</Flex>
</MenuItem>
</MenuList>
</Menu>
);
}

View File

@@ -1,157 +0,0 @@
'use client';
/* eslint-disable */
import AdminNavbarLinks from './NavbarLinksAdmin';
import { isWindowAvailable } from '@/utils/navigation';
import {
Box,
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
Flex,
Link,
useColorModeValue
} from '@chakra-ui/react';
import { useState, useEffect } from 'react';
export default function AdminNavbar(props: {
logoText: string;
brandText: string;
userDetails: { [x: string]: any } | null;
onOpen: (...args: any[]) => any;
[x: string]: any;
}) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
isWindowAvailable() && window.addEventListener('scroll', changeNavbar);
return () => {
isWindowAvailable() && window.removeEventListener('scroll', changeNavbar);
};
});
const { brandText, userDetails } = props;
// Here are all the props that may change depending on navbar's type or state.(secondary, variant, scrolled)
let mainText = useColorModeValue('#120F43', 'white');
let secondaryText = useColorModeValue('gray.700', 'white');
let navbarPosition = 'fixed' as const;
let navbarFilter = 'none';
let navbarBackdrop = 'blur(20px)';
let navbarShadow = 'none';
let navbarBg = useColorModeValue(
'rgba(244, 247, 254, 0.2)',
'rgba(11,20,55,0.5)'
);
let navbarBorder = 'transparent';
let secondaryMargin = '0px';
let gap = '0px';
const changeNavbar = () => {
if (isWindowAvailable() && window.scrollY > 1) {
setScrolled(true);
} else {
setScrolled(false);
}
};
return (
<Box
zIndex="100"
position={navbarPosition}
boxShadow={navbarShadow}
bg={navbarBg}
borderColor={navbarBorder}
filter={navbarFilter}
backdropFilter={navbarBackdrop}
backgroundPosition="center"
backgroundSize="cover"
borderRadius="16px"
borderWidth="1.5px"
borderStyle="solid"
transitionDelay="0s, 0s, 0s, 0s"
transitionDuration=" 0.25s, 0.25s, 0.25s, 0s"
transition-property="box-shadow, background-color, filter, border"
transitionTimingFunction="linear, linear, linear, linear"
alignItems={{ xl: 'center' }}
display={'flex'}
minH="75px"
justifyContent={{ xl: 'center' }}
lineHeight="25.6px"
mx="auto"
mt={secondaryMargin}
pb="8px"
right={{ base: '12px', md: '30px', lg: '30px', xl: '30px' }}
ps={{
base: '8px',
md: '12px'
}}
pt="8px"
top={{ base: '12px', md: '16px', xl: '18px' }}
w={{
base: 'calc(100vw - 8%)',
md: 'calc(100vw - 8%)',
lg: 'calc(100vw - 6%)',
xl: 'calc(100vw - 350px)',
'2xl': 'calc(100vw - 365px)'
}}
>
<Flex
w="100%"
flexDirection={{
base: 'row',
md: 'row'
}}
alignItems={{ xl: 'center' }}
mb={gap}
>
<Box>
<Breadcrumb>
<BreadcrumbItem
color={secondaryText}
fontSize={{ base: 'xs', md: 'sm' }}
mb={{ base: '0px', md: '5px' }}
>
<BreadcrumbLink href="#" color={secondaryText}>
Pages
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem
color={secondaryText}
fontSize={{ base: 'xs', md: 'sm' }}
>
<BreadcrumbLink href="#" color={secondaryText}>
{brandText}
</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
{/* Here we create navbar brand, based on route name */}
<Link
color={mainText}
href="#"
bg="inherit"
borderRadius="inherit"
fontWeight="bold"
fontSize={{ base: 'lg', md: '34px' }}
p="0px"
_hover={{ color: { mainText } }}
_active={{
bg: 'inherit',
transform: 'none',
borderColor: 'transparent'
}}
_focus={{
boxShadow: 'none'
}}
>
{brandText}
</Link>
</Box>
<Box ms="auto" w={{ sm: '154px', md: 'unset' }}>
<AdminNavbarLinks />
</Box>
</Flex>
</Box>
);
}

View File

@@ -1,403 +0,0 @@
/* eslint-disable */
'use client';
import logo from '/public/logo-horizon-boilerplate.png';
import {
Image,
Button,
Flex,
Icon,
Link,
Menu,
MenuButton,
MenuItem,
MenuList,
Text,
useColorModeValue,
} from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';
import { IoIosStar, IoMdTrophy } from 'react-icons/io';
import { IoMenuOutline } from 'react-icons/io5';
import { MdChevronRight, MdPrivacyTip } from 'react-icons/md';
export default function AdminNavbar(props) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
window.addEventListener('scroll', changeNavbar);
return () => {
window.removeEventListener('scroll', changeNavbar);
};
});
const { secondary, message } = props;
// Here are all the props that may change depending on navbar's type or state.(secondary, variant, scrolled)
let textColor = useColorModeValue('#120F43', 'white');
let borderColor = useColorModeValue('gray.300', 'white');
let navbarPosition = 'fixed';
let navbarFilter = 'none';
let navbarShadow = '45px 76px 113px 7px rgba(112, 144, 176, 0.08)';
let navbarBorder = 'transparent';
let paddingX = '15px';
let gap = '0px';
let navbarTop = '0px';
let menuBg = useColorModeValue('white', 'navy.800');
const changeNavbar = () => {
if (window.scrollY > 1) {
setScrolled(true);
} else {
setScrolled(false);
}
};
return (
<Flex
position={navbarPosition}
boxShadow={navbarShadow}
bg="white"
direction="column"
borderColor={navbarBorder}
filter={navbarFilter}
backgroundPosition="center"
backgroundSize="cover"
zIndex="200"
borderStyle="solid"
alignItems={{ xl: 'center' }}
display={secondary ? 'block' : 'flex'}
justifyContent={{ xl: 'center' }}
lineHeight="25.6px"
mx="auto"
left="50%"
transform="translate(-50%,0px)"
w="100%"
top={navbarTop}
>
{/* Misc */}
<Flex
w="100%"
display={{ base: 'none', lg: 'flex' }}
bg="#F3F5FA"
justifyContent="center"
>
<Flex
w={{
base: 'calc(100vw - 4%)',
md: 'calc(100vw - 4%)',
lg: '100vw',
xl: 'calc(100vw - 250px)',
'2xl': '1200px',
}}
px={{
sm: paddingX,
md: '10px',
lg: '12px',
}}
py="4px"
gap="40px"
justifyContent="center"
>
<Flex direction="row" alignItems="center">
<Icon
me="6px"
w="12px"
h="12px"
color="brand.500"
as={MdPrivacyTip}
/>
<Text fontSize="xs" fontWeight="500" h="100%" color="gray.500">
Founded in EU. We respect your privacy.
</Text>
</Flex>
<Flex direction="row" alignItems="center">
<Icon me="1px" w="12px" h="12px" color="brand.500" as={IoIosStar} />
<Icon me="1px" w="12px" h="12px" color="brand.500" as={IoIosStar} />
<Icon me="1px" w="12px" h="12px" color="brand.500" as={IoIosStar} />
<Icon me="1px" w="12px" h="12px" color="brand.500" as={IoIosStar} />
<Icon me="6px" w="12px" h="12px" color="brand.500" as={IoIosStar} />
<Text fontSize="xs" fontWeight="500" h="100%" color="gray.500">
Loved by 80,000+ users worldwide
</Text>
</Flex>
<Flex direction="row" alignItems="center">
<Icon
me="6px"
w="12px"
h="12px"
color="brand.500"
as={IoMdTrophy}
/>
<Text fontSize="xs" fontWeight="500" h="100%" color="gray.500">
#1 NextJS boilerplate & admin template
</Text>
</Flex>
</Flex>
</Flex>
{/* Misc */}
<Flex
w={{
base: 'calc(100vw - 4%)',
md: 'calc(100vw - 4%)',
lg: '100vw',
xl: 'calc(100vw - 250px)',
'2xl': '1200px',
}}
px={{
sm: paddingX,
md: '10px',
lg: '12px',
}}
py="20px"
ps={{
xl: '12px',
}}
flexDirection={{
sm: 'row',
md: 'row',
}}
alignItems="center"
justify="space-between"
mb={gap}
>
<Link
display={'flex'}
alignItems="center"
justifyContent={'center'}
href="/"
>
<Image
alt=" "
w="36px"
src={logo.src}
/>
<Text ms="8px" me="10px" fontWeight="800" color="#120F43">
Horizon UI Boilerplate
</Text>
</Link>
<Flex>
<Link
display={{ base: 'none', lg: 'block' }}
href="/dashboard/signin"
color="gray.600"
fontSize="sm"
fontWeight="500"
letterSpacing="0px"
me="30px"
my="auto"
>
Generator
</Link>
<Link
display={{ base: 'none', lg: 'block' }}
href="/#features"
color="gray.600"
fontSize="sm"
fontWeight="500"
letterSpacing="0px"
me="30px"
my="auto"
>
Features
</Link>
<Link
display={{ base: 'none', lg: 'block' }}
href="/pricing"
color="gray.600"
fontSize="sm"
fontWeight="500"
letterSpacing="0px"
me="30px"
my="auto"
>
Pricing
</Link>
<Link
display={{ base: 'none', lg: 'block' }}
href="#faqs"
color="gray.600"
fontSize="sm"
fontWeight="500"
letterSpacing="0px"
me="30px"
my="auto"
>
FAQs
</Link>
<Menu>
<MenuButton
display={{ base: 'block', xl: 'none' }}
p="0px !important"
maxH="20px"
maxW="20px"
alignContent="end"
>
<Icon
display={{ base: 'block', lg: 'none' }}
as={IoMenuOutline}
color={textColor}
w="20px"
h="20px"
_hover={{ cursor: 'pointer' }}
/>
</MenuButton>
<MenuList
p="0px"
mt="10px"
borderRadius="10px"
border="1px solid"
borderColor="#CBD5E0"
bg={menuBg}
>
<Flex flexDirection="column" p="10px">
<MenuItem
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
borderRadius="8px"
px="14px"
>
<Link
href="/dashboard/signin"
color="gray.600"
fontSize="md"
fontWeight="500"
me="30px"
my="auto"
>
Generator
</Link>
</MenuItem>
<MenuItem
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
borderRadius="8px"
px="14px"
>
<Link
href="/#features"
color="gray.600"
fontSize="md"
fontWeight="500"
me="30px"
my="auto"
>
Features
</Link>
</MenuItem>
<MenuItem
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
color="red.400"
borderRadius="8px"
>
<Link
href="/pricing"
color="gray.600"
fontSize="md"
fontWeight="500"
me="30px"
my="auto"
>
Pricing
</Link>
</MenuItem>
<MenuItem
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
color="red.400"
borderRadius="8px"
>
<Link
href="#faqs"
color="gray.600"
fontSize="md"
fontWeight="500"
me="30px"
my="auto"
>
FAQs
</Link>
</MenuItem>
<MenuItem
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
color="red.400"
borderRadius="8px"
>
<Link
href="/dashboard/signin"
color={textColor}
fontSize="md"
fontWeight="600"
me="18px"
my="auto"
letterSpacing="0px"
>
Login
</Link>
</MenuItem>
<Button
variant="transparent"
border="1px solid"
borderColor={borderColor}
color={textColor}
fontSize="md"
borderRadius="45px"
bg="transparent"
my="auto"
>
<Link href="/dashboard/signin">
Get started for Free
<Icon
as={MdChevronRight}
mt="3px"
ms="5px"
h="16px"
w="16px"
/>
</Link>
</Button>
</Flex>
</MenuList>
</Menu>
</Flex>
<Flex display={{ base: 'none', lg: 'flex' }}>
<Link
href="/dashboard/signin"
color={textColor}
fontSize="sm"
fontWeight="600"
me="18px"
letterSpacing="0px"
my="auto"
>
Login
</Link>
<Link href="/dashboard/signin">
<Button
variant="transparent"
border="1px solid"
borderColor={borderColor}
color={textColor}
fontSize="sm"
borderRadius="45px"
px="18px"
py="12px"
bg="transparent"
my="auto"
>
{' '}
Get started for Free
<Icon as={MdChevronRight} mt="3px" h="16px" w="16px" />
</Button>
</Link>
</Flex>
</Flex>
{secondary ? <Text color="white">{message}</Text> : null}
</Flex>
);
}

View File

@@ -1,181 +0,0 @@
'use client';
import { useSupabase } from '@/app/supabase-provider';
import { routes } from '@/components/routes';
import { SidebarResponsive } from '@/components/sidebar/Sidebar';
import { OpenContext, UserContext } from '@/contexts/layout';
import { handleRequest } from '@/utils/auth-helpers/client';
import { SignOut } from '@/utils/auth-helpers/server';
import { getRedirectMethod } from '@/utils/auth-helpers/settings';
import {
Avatar,
Box,
Button,
ButtonGroup,
Flex,
Icon,
Link,
Menu,
MenuButton,
MenuList,
useColorModeValue
} from '@chakra-ui/react';
import { usePathname, useRouter } from 'next/navigation';
import { useContext } from 'react';
import { MdOutlineLogout, MdHelpOutline } from 'react-icons/md';
export default function HeaderLinks(props?: { [x: string]: any }) {
const { open, setOpen } = useContext(OpenContext);
const user = useContext(UserContext);
const router = getRedirectMethod() === 'client' ? useRouter() : null;
// Chakra Color Mode
const navbarIcon = useColorModeValue('gray.500', 'white');
let menuBg = useColorModeValue('white', 'navy.800');
const textColor = useColorModeValue('#120F43', 'white');
const shadow = useColorModeValue(
'14px 17px 40px 4px rgba(112, 144, 176, 0.18)',
'0px 41px 75px #081132'
);
const buttonBg = useColorModeValue('transparent', 'navy.800');
const hoverButton = useColorModeValue(
{ bg: 'gray.100' },
{ bg: 'whiteAlpha.100' }
);
const activeButton = useColorModeValue(
{ bg: 'gray.200' },
{ bg: 'whiteAlpha.200' }
);
return (
<Flex
zIndex="100"
w={{ sm: '100%', md: 'auto' }}
alignItems="center"
flexDirection="row"
bg={menuBg}
flexWrap={'unset'}
p="10px"
pl="16px"
borderRadius="30px"
boxShadow={shadow}
>
<SidebarResponsive routes={routes} />
<Menu>
<MenuButton p="0px" me="10px">
<Icon
mt="-5px"
as={MdHelpOutline}
color={navbarIcon}
w="18px"
h="18px"
/>
</MenuButton>
<MenuList
boxShadow={shadow}
p="20px"
borderRadius="20px"
bg={menuBg}
border="none"
mt="22px"
minW={{ base: 'unset' }}
maxW={{ base: '360px', md: 'unset' }}
>
{/* <Flex bgImage={navImage} borderRadius="16px" mb="28px" alt="" /> */}
<Flex flexDirection="column" rowGap="10px">
<Link w="100%" href="/pricing">
<Button
bg={buttonBg}
border="1px solid"
color={textColor}
borderColor={useColorModeValue('gray.200', 'whiteAlpha.100')}
fontSize="sm"
borderRadius="45px"
w="100%"
minW="44px"
h="44px"
_placeholder={{ color: 'gray.500' }}
_hover={hoverButton}
_active={activeButton}
_focus={activeButton}
>
Pricing Plans
</Button>
</Link>
<Link w="100%" href="mailto:hello@horizon-ui.com">
<Button
bg={buttonBg}
border="1px solid"
color={textColor}
borderColor={useColorModeValue('gray.200', 'whiteAlpha.100')}
fontSize="sm"
borderRadius="45px"
w="100%"
minW="44px"
h="44px"
_placeholder={{ color: 'gray.500' }}
_hover={hoverButton}
_active={activeButton}
_focus={activeButton}
>
Help & Support
</Button>
</Link>
<Link w="100%" href="/#faqs">
<Button
bg={buttonBg}
border="1px solid"
color={textColor}
borderColor={useColorModeValue('gray.200', 'whiteAlpha.100')}
fontSize="sm"
borderRadius="45px"
w="100%"
minW="44px"
h="44px"
_placeholder={{ color: 'gray.500' }}
_hover={hoverButton}
_active={activeButton}
_focus={activeButton}
>
FAQs & More
</Button>
</Link>
</Flex>
</MenuList>
</Menu>
<form onSubmit={(e) => handleRequest(e, SignOut, router)}>
<input type="hidden" name="pathName" value={usePathname()} />
<Button
type="submit"
bg="transparent"
p="0px"
pt="3px"
_hover={{ background: 'transparent' }}
_active={{ background: 'transparent' }}
_focus={{ background: 'transparent' }}
>
<Box
cursor="pointer"
_hover={{ bg: 'none' }}
_focus={{ bg: 'none' }}
color="red.400"
borderRadius="8px"
me="10px"
>
{/* <Text> {`${props.userDetails?.avatar_url}`}</Text> */}
<Icon
mt="-5px"
as={MdOutlineLogout}
color={navbarIcon}
w="20px"
h="20px"
/>
</Box>
</Button>
</form>
<Link w="100%" href="/dashboard/settings">
<Avatar h="40px" w="40px" src={user.user_metadata.avatar_url} />
</Link>
</Flex>
);
}

View File

@@ -1,978 +0,0 @@
'use client';
// @ts-nocheck
import { FooterWebsite } from '../footer/FooterWebsite';
import Card from '@/components/card/Card';
import Faq from '@/components/landing/faq';
import InnerContent from '@/components/layout/innerContent';
import NavbarFixed from '@/components/navbar/NavbarFixed';
import { Database } from '@/types_db';
import { getStripe } from '@/utils/stripe/client';
import {
Badge,
Button,
Flex,
Icon,
Link,
SimpleGrid,
Text,
useColorModeValue
} from '@chakra-ui/react';
import { User } from '@supabase/supabase-js';
import { usePathname, useRouter } from 'next/navigation';
import React, { useState } from 'react';
import {
FaCcVisa,
FaCcMastercard,
FaCcPaypal,
FaCcAmex,
FaCcApplePay
} from 'react-icons/fa';
import {
MdChevronRight,
MdCheckCircle,
MdAttachMoney,
MdLock,
MdOutlineDoDisturbOn
} from 'react-icons/md';
import { checkoutWithStripe } from '@/utils/stripe/server';
import { getErrorRedirect } from '@/utils/helpers';
type Subscription = Database['public']['Tables']['subscriptions']['Row'];
type Product = Database['public']['Tables']['products']['Row'];
type Price = Database['public']['Tables']['prices']['Row'];
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
interface Props {
user: User | null | undefined;
products: ProductWithPrices[];
subscription: SubscriptionWithProduct | null;
}
export default function Pricing({ user, products, subscription }: Props) {
const router = useRouter();
const currentPath = usePathname();
const [priceIdLoading, setPriceIdLoading] = useState<string>();
const handleCheckout = async (price: Price) => {
setPriceIdLoading(price.id);
if (!user) {
setPriceIdLoading(undefined);
return router.push('/signin/signup');
}
const { errorRedirect, sessionId } = await checkoutWithStripe(
price,
currentPath
);
if (errorRedirect) {
setPriceIdLoading(undefined);
return router.push(errorRedirect);
}
if (!sessionId) {
setPriceIdLoading(undefined);
return router.push(
getErrorRedirect(
currentPath,
'An unknown error occurred.',
'Please try again later or contact a system administrator.'
)
);
}
const stripe = await getStripe();
stripe?.redirectToCheckout({ sessionId });
setPriceIdLoading(undefined);
};
const [version, setVersion] = useState('monthly');
const textColor = useColorModeValue('#120F43', 'white');
const brandColor = useColorModeValue('brand.500', 'white');
const brandColorPrice = useColorModeValue('brand.500', 'white');
const card = useColorModeValue('#fff', 'rgba(255, 255, 255, 0.05)');
return (
<Flex
id="pricing"
bgSize="cover"
w="100%"
direction={{ base: 'column' }}
pt={{ base: '120px', md: '180px' }}
overflow="hidden"
position="relative"
>
<NavbarFixed />
<InnerContent
zIndex="1"
maxW={{ base: '100%', md: '100%', xl: '1170px' }}
pb={{ base: '60px', md: '100px' }}
>
{/* Title */}
<Flex
px={{ base: '20px', md: '0px' }}
w="100%"
mb="40px"
direction={{ base: 'column' }}
>
<Flex
direction="column"
textAlign="start"
px={{ base: '20px', md: '40px', xl: '0px' }}
mb={{ base: '0px', lg: '30px' }}
justify="center"
align="center"
>
<Text
as="h3"
textAlign={{ base: 'center', lg: 'center' }}
fontWeight="700"
letterSpacing="2px"
color={brandColorPrice}
fontSize={{ base: 'xs', md: 'md' }}
w="100%"
mb="10px"
>
PRICING PLANS
</Text>
<Text
as="h2"
textAlign={{ base: 'center', lg: 'center' }}
color={textColor}
fontWeight="800"
fontSize={{ base: '28px', md: '40px', lg: '40px', xl: '48px' }}
lineHeight={{ base: '38px', md: '50px', lg: '50px', xl: '60px' }}
w={{ base: '100%', md: '90%', lg: '80%', xl: '74%' }}
>
Create outstanding Essays for less than a Netflix subscription per
month
</Text>
</Flex>
</Flex>
<SimpleGrid
px={{ base: '20px', md: '0px' }}
w="100%"
columns={{ base: 1, lg: 3 }}
gap="20px"
mb="20px"
>
<Card
borderRadius="16px"
bg={card}
maxW="377px"
mx="auto"
alignItems={{ base: 'start', lg: 'center' }}
p={{ base: '16px', md: '26px' }}
pt={{ base: '26px', md: '36px' }}
flexDirection="column"
>
<Flex mb="20px" mx="auto">
<Text
fontSize="22px"
letterSpacing="0px"
textAlign="center"
fontWeight="700"
color={textColor}
>
Demo Plan
</Text>
</Flex>
<Flex
zIndex="1"
px={{ base: '18px', md: '34px' }}
pt="40px"
pb="40px"
borderRadius="16px"
bg="#F3F5FA"
mb="40px"
direction="column"
w="100%"
>
<Flex mb="30px" direction="row" justify="center">
<Text
color="#120F43"
fontSize={{ base: '48px', md: '54px' }}
lineHeight="100%"
letterSpacing="0px"
fontWeight="extrabold"
>
Free
</Text>
</Flex>
<Link href="/dashboard/signin">
<Button
py="20px"
px="16px"
fontSize="sm"
variant="checkout"
mx="auto"
borderRadius="45px"
w="100%"
h="54px"
>
{subscription ? 'Manage' : 'Get started now'}
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Link>
</Flex>
<Flex w={{ base: '100%', xl: '100%' }} direction="column">
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Standard Essays
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 4 Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 300 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="gray.400"
as={MdOutlineDoDisturbOn}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="gray.400"
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="gray.400"
as={MdOutlineDoDisturbOn}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="gray.400"
letterSpacing="0px"
>
Academic Citation formats (APA, etc)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="gray.400"
as={MdOutlineDoDisturbOn}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="gray.400"
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="gray.400"
as={MdOutlineDoDisturbOn}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="gray.400"
letterSpacing="0px"
>
Premium features
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="gray.400"
as={MdOutlineDoDisturbOn}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="gray.400"
letterSpacing="0px"
>
Priority Support
</Text>
</Flex>
</Flex>
</Card>
{products.map((product) => {
const price = product?.prices?.find(
(price) => price.id === 'price_1P3gGXGx8VbJPRgzdEZODy8K'
);
if (product.id === 'prod_PtTCPDFZbburMa') {
if (!price) return null;
return (
<Card
key={product.id}
borderRadius="16px"
bg="#120F43"
maxW="377px"
mx="auto"
alignItems={{ base: 'start', lg: 'center' }}
p={{ base: '16px', md: '26px' }}
pt={{ base: '26px', md: '36px' }}
flexDirection="column"
>
{/* @ts-ignore-nextline */}
<Flex mb="20px" mx="auto">
<Text
fontSize="22px"
letterSpacing="0px"
textAlign="center"
fontWeight="700"
color="white"
>
{product.name?.toString()}
</Text>
</Flex>
<Flex
zIndex="1"
px={{ base: '18px', md: '34px' }}
pt="40px"
pb="40px"
borderRadius="16px"
bg="#120F43"
boxShadow="0px 8px 25px -4px rgba(255, 255, 255, 0.30) inset"
mb="40px"
direction="column"
w="100%"
>
<Flex mb="30px" direction="row" justify="center">
<Text
color="white"
fontSize={{ base: '48px', md: '54px' }}
lineHeight="100%"
letterSpacing="0px"
fontWeight="extrabold"
>
$
{price.unit_amount !== null
? price.unit_amount / 100
: price.unit_amount}
</Text>
<Flex direction="column">
<Text
color="white"
letterSpacing="0px"
fontWeight="700"
fontSize="sm"
mt="auto"
>
{version !== 'yearly' ? '/month' : '/month'}
</Text>
{/* <Text
color="white"
letterSpacing="0px"
fontWeight="500"
fontSize="sm"
textDecoration="line-through"
>
{version !== 'yearly' ? 'reg. $24' : 'reg. $24'}
</Text> */}
</Flex>
</Flex>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="checkoutDark"
mx="auto"
borderRadius="45px"
w="100%"
h="54px"
onClick={() => handleCheckout(price)}
>
{subscription ? 'Manage' : 'Get started now'}
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Flex>
{/* Features */}
<Flex w={{ base: '100%', xl: '100%' }} direction="column">
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Unlimited Premium Essays / month
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Access to 12+ Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Up to 1500 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Academic Citation formats (APA, etc)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Exceptional Essays in seconds
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Easy-to-use Essay Generator
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color="white"
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color="white"
letterSpacing="0px"
>
Priority Support
</Text>
</Flex>
</Flex>
</Card>
);
}
})}
{products.map((product) => {
const price = product?.prices?.find(
(price) => price.id === 'price_1P3gMyGx8VbJPRgzkoB6Fp8F'
);
if (product.id === 'prod_PtTJ6R3RnzmIPX') {
if (!price) return null;
return (
<Card
key={product.id}
borderRadius="16px"
bg={card}
maxW="377px"
mx="auto"
alignItems={{ base: 'start', lg: 'center' }}
p={{ base: '16px', md: '26px' }}
pt={{ base: '26px', md: '36px' }}
flexDirection="column"
>
<Flex mb="20px" mx="auto">
<Text
fontSize="22px"
letterSpacing="0px"
textAlign="center"
fontWeight="700"
color={textColor}
>
{product.name?.toString()}
</Text>
<Badge
display="flex"
bg="#F2EFFF"
alignItems="center"
borderRadius="99px"
px="6px"
pb="8px"
ms="10px"
textColor={brandColor}
>
Save 35%
</Badge>
</Flex>
<Flex
zIndex="1"
px={{ base: '18px', md: '34px' }}
pt="40px"
pb="40px"
borderRadius="16px"
bg="#F3F5FA"
mb="40px"
direction="column"
w="100%"
>
<Flex mb="30px" direction="row" justify="center">
<Text
color={'transparent'}
fontSize={{ base: '48px', md: '54px' }}
lineHeight="100%"
letterSpacing="0px"
fontWeight="extrabold"
bgGradient="linear-gradient(91deg, #3D1DFF 0%, #6147FF 22.40%, #D451FF 46.35%, #EC458D 75.00%, #FFCA8B 100%)"
bgClip="text"
>
$
{price.unit_amount !== null
? price.unit_amount / 100
: price.unit_amount}
</Text>
<Flex direction="column" ms="8px">
<Text
color={textColor}
letterSpacing="0px"
fontWeight="700"
fontSize="sm"
mt="auto"
>
{version !== 'yearly' ? '/year' : '/year'}
</Text>
<Text
color={textColor}
letterSpacing="0px"
fontWeight="500"
textDecoration="line-through"
fontSize="sm"
mt="2px"
>
{version !== 'yearly' ? 'reg.$108' : 'reg.$108'}
</Text>
</Flex>
</Flex>
<Button
py="20px"
px="16px"
fontSize="sm"
variant="checkout"
mx="auto"
borderRadius="45px"
w="100%"
h="54px"
onClick={() => handleCheckout(price)}
>
{subscription ? 'Manage' : 'Get started now'}
<Icon as={MdChevronRight} mt="2px" h="16px" w="16px" />
</Button>
</Flex>
{/* Features */}
<Flex w={{ base: '100%', xl: '100%' }} direction="column">
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Unlimited Premium Essays / year
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Access to 12+ Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 1500 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Citation formats (APA, etc)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Exceptional Essays in seconds
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Easy-to-use Essay Generator
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={brandColor}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize={{ base: 'sm', lg: 'sm', xl: 'md' }}
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Priority Support
</Text>
</Flex>
</Flex>
</Card>
);
}
})}
</SimpleGrid>
<Flex
px={{ base: '20px', md: '0px' }}
direction="column"
alignItems="center"
mt="30px"
>
<Flex alignItems="center" mb="20px">
<Icon
me="4px"
w="24px"
h="24px"
color={textColor}
as={MdAttachMoney}
/>
<Text
as="span"
fontSize="sm"
fontWeight="500"
color={textColor}
letterSpacing="0px"
>
7-Days money back
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon me="4px" w="24px" h="24px" color={textColor} as={MdLock} />
<Text
as="span"
fontSize="sm"
fontWeight="500"
color={textColor}
letterSpacing="0px"
>
Secured AES-256 Encrypted payments powered by Stripe:
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon me="10px" w="30px" h="30px" color={textColor} as={FaCcVisa} />
<Icon
me="10px"
w="30px"
h="30px"
color={textColor}
as={FaCcMastercard}
/>
<Icon
me="10px"
w="30px"
h="30px"
color={textColor}
as={FaCcPaypal}
/>
<Icon
me="10px"
w="30px"
h="30px"
color={textColor}
as={FaCcApplePay}
/>
<Icon w="30px" h="30px" color={textColor} as={FaCcAmex} />
</Flex>
</Flex>
</InnerContent>
<Faq />
<FooterWebsite />
</Flex>
);
}

View File

@@ -1,13 +0,0 @@
'use client';
import theme from '@/theme/theme';
import { CacheProvider } from '@chakra-ui/next-js';
import { ChakraProvider } from '@chakra-ui/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<CacheProvider>
<ChakraProvider theme={theme}>{children}</ChakraProvider>
</CacheProvider>
);
}

View File

@@ -1,88 +0,0 @@
import { IoIosStar } from 'react-icons/io';
import { Flex, Icon, Text, useColorModeValue } from '@chakra-ui/react';
export default function Ratings(props: {
dark?: boolean;
stats: string;
stars?: 1 | 2 | 3 | 4 | 5;
rating: string | number;
}) {
const { rating, stats, stars } = props;
const gray = useColorModeValue('whiteAlpha.300', 'gray.200');
const textColor = useColorModeValue('navy.900', 'white');
return (
<Flex direction="column" align="center" justify="center">
<Text color={gray} mt={{base:"12px", lg:"40px"}} mb="10px" justifySelf={'center'} fontWeight='500'
>
{stats}
</Text>
{stars === 1 ? (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color={gray} />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
) : stars === 2 ? (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color={gray} />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
) : stars === 3 ? (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color={gray} />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color={gray} />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
) : stars === 4 ? (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color={gray} />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
) : stars === 5 ? (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color="#F6AD55" />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
) : (
<Flex align="center" justify={{ base: 'center', md: 'flex-start' }}>
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" color="#F6AD55" />
<Icon as={IoIosStar} h="22px" w="22px" me="8px" color="#F6AD55" />
<Text fontWeight="bold" my="2px" fontSize="lg" color={textColor}>
{rating}
</Text>
</Flex>
)}
</Flex>
);
}

View File

@@ -1,92 +0,0 @@
// Auth Imports
import { IRoute } from '@/types/types';
import { Icon } from '@chakra-ui/react';
import {
MdCreditCard,
MdHome,
MdOutlineManageAccounts,
MdWorkspacePremium,
} from 'react-icons/md';
export const routes: IRoute[] = [
{
name: 'Main Dashboard',
path: '/dashboard/main',
icon: (
<Icon as={MdHome} mt="-7px" width="20px" height="20px" color="inherit" />
),
collapse: false,
},
{
name: 'AI Pages',
path: '/ai-pages',
icon: (
<Icon
as={MdWorkspacePremium}
mt="-7px"
width="20px"
height="20px"
color="inherit"
/>
),
collapse: true,
items: [
{
name: 'AI Generator',
path: '/dashboard/ai-generator',
collapse: false,
},
{
name: 'AI Assistant',
path: '/dashboard/ai-assistant',
collapse: false,
},
{
name: 'AI Chat',
path: '/dashboard/ai-chat',
collapse: false,
},
],
},
{
name: 'Users List',
path: '/dashboard/users-list',
icon: (
<Icon height="24px" viewBox="0 -960 960 960" width="24px" mt="-7px">
<path
fill="currentColor"
d="M640-400q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35ZM400-160v-76q0-21 10-40t28-30q45-27 95.5-40.5T640-360q56 0 106.5 13.5T842-306q18 11 28 30t10 40v76H400Zm86-80h308q-35-20-74-30t-80-10q-41 0-80 10t-74 30Zm154-240q17 0 28.5-11.5T680-520q0-17-11.5-28.5T640-560q-17 0-28.5 11.5T600-520q0 17 11.5 28.5T640-480Zm0-40Zm0 280ZM120-400v-80h320v80H120Zm0-320v-80h480v80H120Zm324 160H120v-80h360q-14 17-22.5 37T444-560Z"
></path>
</Icon>
),
collapse: false,
},
{
name: 'Profile Settings',
path: '/dashboard/settings',
icon: (
<Icon
mt="-7px"
as={MdOutlineManageAccounts}
width="20px"
height="20px"
color="inherit"
/>
),
collapse: false,
},
{
name: 'Subscription',
path: '/dashboard/subscription',
icon: (
<Icon
mt="-7px"
as={MdCreditCard}
width="20px"
height="20px"
color="inherit"
/>
),
collapse: false,
},
];

View File

@@ -1,42 +0,0 @@
'use client';
import { Box } from '@chakra-ui/react';
export const renderTrack = ({ style, ...props }: any) => {
const trackStyle = {
position: 'absolute',
maxWidth: '100%',
transition: 'opacity 200ms ease 0s',
opacity: 0,
background: 'transparent',
bottom: 2,
top: 2,
borderRadius: 3,
right: 0,
};
return <div style={{ ...style, ...trackStyle }} {...props} />;
};
export const renderThumb = ({ style, ...props }: any) => {
const thumbStyle = {
borderRadius: 15,
background: 'rgba(222, 222, 222, .1)',
};
return <div style={{ ...style, ...thumbStyle }} {...props} />;
};
export const renderView = ({ style, ...props }: any) => {
const viewStyle = {
width: '100%',
marginBottom: -22,
};
return (
<Box
me={{ base: '0px !important', '2xl': '-16px !important' }}
transform="translate(0px, 0px)"
boxSizing={'unset'}
pe="15px"
style={{ ...style, ...viewStyle }}
{...props}
/>
);
};

View File

@@ -1,16 +0,0 @@
'use client';
import { Flex, useColorModeValue } from '@chakra-ui/react';
const HSeparator = (props: { variant?: string; [x: string]: any }) => {
const textColor = useColorModeValue('gray.200', 'whiteAlpha.300');
const { variant, ...rest } = props;
return <Flex h="1px" w="100%" bg={textColor} {...rest} />;
};
const VSeparator = (props: { variant?: string; [x: string]: any }) => {
const textColor = useColorModeValue('gray.200', 'whiteAlpha.300');
const { variant, ...rest } = props;
return <Flex w="1px" bg={textColor} {...rest} />;
};
export { HSeparator, VSeparator };

View File

@@ -1,144 +0,0 @@
'use client';
import {
renderThumb,
renderTrack,
renderView
} from '@/components/scrollbar/Scrollbar';
import Content from '@/components/sidebar/components/Content';
import { ApiKeyContext } from '@/contexts/layout';
import { IRoute } from '@/types/types';
import { isWindowAvailable } from '@/utils/navigation';
import {
Box,
Flex,
Drawer,
DrawerBody,
Icon,
useColorModeValue,
DrawerOverlay,
useDisclosure,
DrawerContent,
DrawerCloseButton
} from '@chakra-ui/react';
import React, { PropsWithChildren, useContext } from 'react';
import { Scrollbars } from 'react-custom-scrollbars-2';
import { IoMenuOutline } from 'react-icons/io5';
export interface SidebarProps extends PropsWithChildren {
routes: IRoute[];
[x: string]: any;
}
function Sidebar(props: SidebarProps) {
const { routes } = props;
const { apiKey, setApiKey } = useContext(ApiKeyContext);
let variantChange = '0.2s linear';
let shadow = useColorModeValue(
'14px 17px 40px 4px rgba(112, 144, 176, 0.08)',
'unset'
);
let sidebarBg = useColorModeValue('white', 'navy.800');
let sidebarRadius = '14px';
let sidebarMargins = '0px';
return (
<Box display={{ base: 'none', xl: 'block' }} position="fixed" minH="100%">
<Box
bg={sidebarBg}
transition={variantChange}
w="285px"
ms={{
sm: '16px'
}}
my={{
sm: '16px'
}}
h="calc(100vh - 32px)"
m={sidebarMargins}
borderRadius={sidebarRadius}
minH="100%"
overflowX="hidden"
boxShadow={shadow}
>
<Scrollbars
autoHide
renderTrackVertical={renderTrack}
renderThumbVertical={renderThumb}
renderView={renderView}
universal={true}
>
<Content setApiKey={setApiKey} routes={routes} />
</Scrollbars>
</Box>
</Box>
);
}
// -------------- Sidebar Function for Navbar burger --------------
export function SidebarResponsive(props: SidebarProps) {
let sidebarBackgroundColor = useColorModeValue('white', 'navy.800');
let menuColor = useColorModeValue('gray.400', 'white');
const { apiKey, setApiKey } = useContext(ApiKeyContext);
// SIDEBAR
const { isOpen, onOpen, onClose } = useDisclosure();
const { routes } = props;
return (
<Flex display={{ sm: 'flex', xl: 'none' }} alignItems="center">
<Flex w="max-content" h="max-content" onClick={onOpen}>
<Icon
as={IoMenuOutline}
color={menuColor}
my="auto"
w="20px"
h="20px"
me="10px"
_hover={{ cursor: 'pointer' }}
/>
</Flex>
<Drawer
isOpen={isOpen}
onClose={onClose}
placement={
isWindowAvailable() && document.documentElement.dir === 'rtl'
? 'right'
: 'left'
}
>
<DrawerOverlay />
<DrawerContent
w="285px"
maxW="285px"
ms={{
sm: '16px'
}}
my={{
sm: '16px'
}}
borderRadius="16px"
bg={sidebarBackgroundColor}
>
<DrawerCloseButton
zIndex="3"
onClick={onClose}
_focus={{ boxShadow: 'none' }}
_hover={{ boxShadow: 'none' }}
/>
<DrawerBody maxW="285px" px="0rem" pb="0">
<Scrollbars
autoHide
renderTrackVertical={renderTrack}
renderThumbVertical={renderThumb}
renderView={renderView}
universal={true}
>
<Content setApiKey={setApiKey} routes={routes} />
</Scrollbars>
</DrawerBody>
</DrawerContent>
</Drawer>
</Flex>
);
}
export default Sidebar;

View File

@@ -1,38 +0,0 @@
'use client';
import logo from '/public/logo-horizon-boilerplate.png';
import { HSeparator } from '@/components/separator/Separator';
import { Flex, Image, Link, Text } from '@chakra-ui/react';
export function SidebarBrand() {
return (
<Flex alignItems="center" flexDirection="column" ps="24px">
<Link
display={'flex'}
alignItems="center"
justifyContent={'center'}
href="/"
mb="34px"
>
<Image
alt=" "
w="36px"
src={logo.src}
/>
<Text
ms="8px"
me="10px"
fontWeight="800"
fontSize={'17px'}
letterSpacing="-0.2px"
color="#120F43"
>
Horizon UI Boilerplate
</Text>
</Link>
<HSeparator mb="20px" w="310px" />
</Flex>
);
}
export default SidebarBrand;

View File

@@ -1,111 +0,0 @@
'use client';
// Custom components
import { useSupabase } from '@/app/supabase-provider';
import Brand from '@/components/sidebar/components/Brand';
import Links from '@/components/sidebar/components/Links';
import SidebarCard from '@/components/sidebar/components/SidebarCard';
import { UserContext } from '@/contexts/layout';
import { IRoute } from '@/types/types';
import {
Avatar,
Box,
Button,
Flex,
Icon,
Stack,
Text,
useColorModeValue
} from '@chakra-ui/react';
import { useRouter } from 'next/navigation';
import { PropsWithChildren, useContext } from 'react';
import { FiLogOut } from 'react-icons/fi';
// FUNCTIONS
interface SidebarContent extends PropsWithChildren {
routes: IRoute[];
[x: string]: any;
}
function SidebarContent(props: SidebarContent) {
const router = useRouter();
const { supabase } = useSupabase();
const { routes, setApiKey } = props;
const user = useContext(UserContext);
console.log(user.user_metadata.avatar_url);
const textColor = useColorModeValue('#120F43', 'white');
const borderColor = useColorModeValue('gray.200', 'whiteAlpha.300');
const shadowPillBar = useColorModeValue(
'4px 17px 40px 4px rgba(112, 144, 176, 0.08)',
'none'
);
return (
<Flex
direction="column"
height="100%"
pt="36px"
pb="26px"
borderRadius="30px"
maxW="285px"
w="100%"
>
<Brand />
<Stack direction="column" mb="auto" mt="8px" ps="20px" pe="16px">
<Box ps="0px" pe={{ md: '0px', '2xl': '0px' }}>
<Links routes={routes} />
</Box>
</Stack>
<Box
mt="60px"
width={'100%'}
display={'flex'}
justifyContent={'center'}
ps="20px"
pe="20px"
>
<SidebarCard />
</Box>
<Flex
mt="20px"
justifyContent="center"
alignItems="center"
boxShadow={shadowPillBar}
borderRadius="30px"
p="14px"
px="34px"
>
<Avatar
h="34px"
w="34px"
me="10px"
src={user.user_metadata.avatar_url}
/>
<Text color={textColor} fontSize="sm" fontWeight="700" me="10px">
{user.user_metadata.full_name ? user.user_metadata.full_name : 'User'}
</Text>
<Button
ms="auto"
variant="transparent"
border="1px solid"
borderColor={borderColor}
borderRadius="full"
w="34px"
h="34px"
px="0px"
minW="34px"
justifyContent={'center'}
alignItems="center"
onClick={(e) => {
supabase.auth.signOut();
router.push('/');
}}
>
<Icon as={FiLogOut} width="16px" height="16px" color="inherit" />
</Button>
</Flex>
</Flex>
);
}
export default SidebarContent;

View File

@@ -1,823 +0,0 @@
'use client';
/* eslint-disable */
import NavLink from '@/components/link/NavLink';
import {
PlanContext,
ProductsContext,
UserContext,
UserDetailsContext
} from '@/contexts/layout';
import modalImage from '@/public/Modal.png';
import { IRoute } from '@/types/types';
import { Database } from '@/types_db';
import { getRedirectMethod } from '@/utils/auth-helpers/settings';
import { getErrorRedirect } from '@/utils/helpers';
import { getStripe } from '@/utils/stripe/client';
import { checkoutWithStripe } from '@/utils/stripe/server';
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Badge,
Box,
Button,
Flex,
HStack,
Icon,
Image,
List,
ListItem,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
Text,
useColorModeValue,
useDisclosure
} from '@chakra-ui/react';
import { usePathname, useRouter } from 'next/navigation';
import { PropsWithChildren, useCallback, useContext, useState } from 'react';
import { FaCircle } from 'react-icons/fa';
import { IoIosStar, IoMdAdd } from 'react-icons/io';
import { MdCheckCircle, MdChevronRight } from 'react-icons/md';
interface SidebarLinksProps extends PropsWithChildren {
routes: IRoute[];
[x: string]: any;
}
type Price = Database['public']['Tables']['prices']['Row'];
export function SidebarLinks(props: SidebarLinksProps) {
const pathname = usePathname();
const textColor = useColorModeValue('#120F43', 'white');
let activeColor = useColorModeValue('#120F43', 'white');
let inactiveColor = useColorModeValue('gray.500', 'gray.500');
let borderColor = useColorModeValue('gray.200', 'whiteAlpha.300');
let activeIcon = useColorModeValue('brand.500', 'white');
let iconColor = useColorModeValue('#120F43', 'white');
const { isOpen, onOpen, onClose } = useDisclosure();
// verifies if routeName is the one active (in browser input)
const activeRoute = useCallback(
(route: string | { [x: string]: any }) => {
let foundActive = 0;
if (typeof route === 'string') {
return pathname?.includes(route);
} else if (route?.items) {
route.items.map((item: { [x: string]: any }) => {
if (pathname?.includes(item.path)) foundActive = foundActive + 1;
});
}
if (foundActive > 0) return true;
else return false;
},
[pathname]
);
const router = getRedirectMethod() === 'client' ? useRouter() : null;
const { routes } = props;
const user = useContext(UserContext);
const [priceIdLoading, setPriceIdLoading] = useState<string>();
const { plan, setPlan } = useContext(PlanContext);
const products = useContext(ProductsContext);
const currentPath = usePathname();
// this function creates the links and collapses that appear in the sidebar (left menu)
const createLinks = (routes: IRoute[]) => {
const handleCheckout = async (price: Price) => {
setPriceIdLoading(price.id);
if (!user) {
setPriceIdLoading(undefined);
return router.push('/dashboard/signin/signup');
}
const { errorRedirect, sessionId } = await checkoutWithStripe(
price,
currentPath
);
if (errorRedirect) {
setPriceIdLoading(undefined);
return router.push(errorRedirect);
}
if (!sessionId) {
setPriceIdLoading(undefined);
return router.push(
getErrorRedirect(
currentPath,
'An unknown error occurred.',
'Please try again later or contact a system administrator.'
)
);
}
const stripe = await getStripe();
stripe?.redirectToCheckout({ sessionId });
setPriceIdLoading(undefined);
};
return routes.map((route, key) => {
if (route.collapse && !route.invisible) {
return (
<Accordion
allowToggle
defaultIndex={activeRoute(route) ? 0 : 1}
key={key}
>
<AccordionItem border="none" mb="14px" key={key}>
<AccordionButton
display="flex"
alignItems="center"
mb="4px"
justifyContent="center"
_hover={{
bg: 'unset'
}}
_focus={{
boxShadow: 'none'
}}
borderRadius="8px"
w="100%"
py="0px"
ms={0}
>
{route.icon ? (
<Flex align="center" justifyContent="space-between" w="100%">
<HStack spacing={activeRoute(route) ? '22px' : '26px'}>
<Flex
w="100%"
alignItems="center"
justifyContent="center"
>
<Box
color={
activeRoute(route) ? activeIcon : inactiveColor
}
me="12px"
mt="6px"
>
{route.icon}
</Box>
<Text
me="auto"
color={activeRoute(route) ? activeColor : 'gray.500'}
fontWeight="500"
letterSpacing="0px"
fontSize="sm"
>
{route.name}
</Text>
</Flex>
</HStack>
<AccordionIcon ms="auto" color={'gray.500'} />
</Flex>
) : (
<Flex pt="0px" pb="10px" alignItems="center" w="100%">
<HStack
spacing={
activeRoute(route.path.toLowerCase()) ? '22px' : '26px'
}
ps="32px"
>
<Text
me="auto"
color={
activeRoute(route.path.toLowerCase())
? activeColor
: inactiveColor
}
fontWeight="500"
letterSpacing="0px"
fontSize="sm"
>
{route.name}
</Text>
</HStack>
<AccordionIcon ms="auto" color={'gray.500'} />
</Flex>
)}
</AccordionButton>
<AccordionPanel py="0px" ps={'8px'}>
<List>
{
route.icon && route.items
? createLinks(route.items) // for bullet accordion links
: route.items
? createAccordionLinks(route.items)
: '' // for non-bullet accordion links
}
</List>
</AccordionPanel>
</AccordionItem>
</Accordion>
);
} else if (!route.invisible) {
return (
<Box key={key}>
{route.icon ? (
<Flex
align="center"
justifyContent="space-between"
w="100%"
maxW="100%"
ps="17px"
mb="0px"
>
<HStack
w="100%"
mb="14px"
spacing={
activeRoute(route.path.toLowerCase()) ? '22px' : '26px'
}
>
{route.path.includes('premium') && !props.subscription ? (
<Flex w="100%">
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay bg="rgba(0, 0, 0, 0.85)" />
<ModalContent
mx="8px"
bg="transparent"
boxShadow="unset"
maxW="unset"
w="unset"
>
<ModalBody p="0px" position={'relative'}>
<Flex>
<Image
display={{ base: 'none', md: 'block' }}
zIndex="98"
borderLeftRadius="16px"
src={modalImage.src}
w="340px"
/>
<Flex
bg="white"
borderLeftRadius={{ base: '16px', md: '0px' }}
borderRightRadius="16px"
direction={'column'}
px={{ base: '30px', md: '42px' }}
py="34px"
w={{ md: '412px', lg: '456px' }}
minW={{ md: '412px', lg: '456px' }}
>
<Text
fontSize="26px"
fontWeight={'800'}
color={textColor}
mb="12px"
>
Upgrade to Unlimited
</Text>
<Text
mb="24px"
fontWeight="500"
fontSize="md"
color="gray.500"
>
Get access to all features and generate
premium and exclusive essays with our
unlimited plan!
</Text>
{/* Features */}
<Flex
w={{ base: '100%', xl: '80%' }}
direction="column"
>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Access to 12+ Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 1500 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Citation formats (APA, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
</Flex>
{/* YEARLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTJ6R3RnzmIPX',
price: 'price_1P3gMyGx8VbJPRgzkoB6Fp8F'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTJ6R3RnzmIPX'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="14px"
px="14px"
cursor="pointer"
mb="20px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="8px"
>
Yearly
</Text>
<Badge
display={{
base: 'flex',
lg: 'none',
xl: 'flex'
}}
colorScheme="green"
borderRadius="4px"
color="green.500"
textTransform={'none'}
letterSpacing="0px"
px="0px"
w="max-content"
>
Save 35%
</Badge>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$5.75
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END YEARLY */}
{/* MONTHLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTCPDFZbburMa',
price: 'price_1P3gGXGx8VbJPRgzdEZODy8K'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTCPDFZbburMa'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="16px"
px="14px"
cursor="pointer"
mb="28px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="4px"
>
Monthly
</Text>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$9
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END MONTHLY */}
{products.map((product: any) => {
const price = product?.prices?.find(
(price: any) => price.id === plan.price
);
if (product.id === plan.product) {
if (!price) return null;
return (
<Button
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
mb="28px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
onClick={() => handleCheckout(price)}
>
Upgrade now
<Icon
as={MdChevronRight}
mt="2px"
h="16px"
w="16px"
/>
</Button>
);
}
})}
<Text
fontSize="xs"
color="gray.500"
fontWeight={'500'}
mx="auto"
mb="5px"
>
Used by 80,000+ users monthly
</Text>
<Flex
direction="row"
alignItems="center"
mx="auto"
>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="6px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Text
fontSize="sm"
fontWeight="800"
h="100%"
color={textColor}
>
4.9
</Text>
</Flex>
</Flex>
</Flex>
</ModalBody>
<ModalCloseButton
borderRadius="full"
color="#120F43"
bg="#F4F6FB !important"
_hover={{ bg: '#E9EDF6 !important' }}
_focus={{ bg: '#F4F6FB !important' }}
_active={{ bg: '#F4F6FB !important' }}
zIndex="99"
/>
</ModalContent>
</Modal>
<Flex
w="100%"
cursor={'pointer'}
onClick={() => onOpen()}
>
<Flex
w="100%"
alignItems="center"
justifyContent="center"
>
<Box
color={
activeRoute(route.path.toLowerCase())
? activeIcon
: inactiveColor
}
me="12px"
mt="6px"
>
{route.icon}
</Box>
<Text
me="auto"
color={
activeRoute(route.path.toLowerCase())
? activeColor
: 'gray.500'
}
fontWeight={
activeRoute(route.path.toLowerCase())
? '700'
: '500'
}
letterSpacing="0px"
fontSize="sm"
>
{route.name}
</Text>
{route.rightElement ? (
<Flex
border="1px solid"
borderColor={borderColor}
borderRadius="full"
w="34px"
h="34px"
justify={'center'}
align="center"
color={iconColor}
ms="auto"
me="10px"
>
<Icon
as={IoMdAdd}
width="20px"
height="20px"
color="inherit"
/>
</Flex>
) : null}
<Badge
display={{ base: 'flex', lg: 'none', xl: 'flex' }}
colorScheme="brand"
borderRadius="25px"
color="brand.500"
textTransform={'none'}
letterSpacing="0px"
px="8px"
>
PRO
</Badge>
</Flex>
</Flex>
</Flex>
) : (
<NavLink
href={
route.layout ? route.layout + route.path : route.path
}
key={key}
styles={{ width: '100%' }}
>
<Flex
w="100%"
alignItems="center"
justifyContent="center"
>
<Box
color={
activeRoute(route.path.toLowerCase())
? activeIcon
: inactiveColor
}
me="12px"
mt="6px"
>
{route.icon}
</Box>
<Text
me="auto"
color={
activeRoute(route.path.toLowerCase())
? activeColor
: 'gray.500'
}
fontWeight={
activeRoute(route.path.toLowerCase())
? '700'
: '500'
}
letterSpacing="0px"
fontSize="sm"
>
{route.name}
</Text>
{route.rightElement ? (
<Flex
border="1px solid"
borderColor={borderColor}
borderRadius="full"
w="34px"
h="34px"
justify={'center'}
align="center"
color={iconColor}
ms="auto"
me="10px"
>
<Icon
as={IoMdAdd}
width="20px"
height="20px"
color="inherit"
/>
</Flex>
) : null}
</Flex>
</NavLink>
)}
</HStack>
</Flex>
) : (
<ListItem ms={0}>
<Flex ps="32px" alignItems="center" mb="8px">
<NavLink
href={route.layout ? route.layout + route.path : route.path}
key={key}
>
<Text
color={
activeRoute(route.path.toLowerCase())
? activeColor
: inactiveColor
}
fontWeight="500"
fontSize="xs"
>
{route.name}
</Text>
</NavLink>
</Flex>
</ListItem>
)}
</Box>
);
}
});
};
// this function creates the links from the secondary accordions (for example auth -> sign-in -> default)
const createAccordionLinks = (routes: IRoute[]) => {
return routes.map((route: IRoute, key: number) => {
return (
<ListItem
ms="28px"
display="flex"
alignItems="center"
mb="10px"
key={key}
>
<NavLink href={route.layout + route.path} key={key}>
<Icon w="6px" h="6px" me="8px" as={FaCircle} color={activeIcon} />
<Text
color={
activeRoute(route.path.toLowerCase())
? activeColor
: inactiveColor
}
fontWeight={
activeRoute(route.path.toLowerCase()) ? 'bold' : 'normal'
}
fontSize="sm"
>
{route.name}
</Text>
</NavLink>
</ListItem>
);
});
};
// BRAND
return <>{createLinks(routes)}</>;
}
export default SidebarLinks;

View File

@@ -1,556 +0,0 @@
'use client';
import {
ProductsContext,
SubscriptionContext,
UserContext
} from '@/contexts/layout';
import modalImage from '@/public/Modal.png';
import SidebarImage from '@/public/SidebarBadge.png';
import { Database } from '@/types_db';
import { getErrorRedirect } from '@/utils/helpers';
import { getStripe } from '@/utils/stripe/client';
import { checkoutWithStripe } from '@/utils/stripe/server';
import {
Badge,
Button,
Flex,
Icon,
Image,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
Text,
useColorModeValue,
useDisclosure
} from '@chakra-ui/react';
import { usePathname, useRouter } from 'next/navigation';
import { useContext, useState } from 'react';
import { IoIosStar } from 'react-icons/io';
import { MdCheckCircle, MdChevronRight } from 'react-icons/md';
type Price = Database['public']['Tables']['prices']['Row'];
interface SidebarCard {
[x: string]: any;
}
export default function SidebarCard(props: SidebarCard) {
const [priceIdLoading, setPriceIdLoading] = useState<string>();
const textColor = useColorModeValue('#120F43', 'white');
const currentPath = usePathname();
const products = useContext(ProductsContext);
const subscription = useContext(SubscriptionContext);
const { isOpen, onOpen, onClose } = useDisclosure();
const [plan, setPlan] = useState({
product: 'prod_PtTCPDFZbburMa',
price: 'price_1P3gGXGx8VbJPRgzdEZODy8K'
});
const borderColor = 'secondaryGray.200';
const router = useRouter();
const handleCheckout = async (price: Price) => {
setPriceIdLoading(price.id);
const user = useContext(UserContext);
if (!user) {
setPriceIdLoading(undefined);
return router.push('/dashboard/signin/signup');
}
const { errorRedirect, sessionId } = await checkoutWithStripe(
price,
currentPath
);
if (errorRedirect) {
setPriceIdLoading(undefined);
return router.push(errorRedirect);
}
if (!sessionId) {
setPriceIdLoading(undefined);
return router.push(
getErrorRedirect(
currentPath,
'An unknown error occurred.',
'Please try again later or contact a system administrator.'
)
);
}
const stripe = await getStripe();
stripe?.redirectToCheckout({ sessionId });
setPriceIdLoading(undefined);
};
if (subscription) {
// -------------- PRO User Card --------------
return (
<Flex
align="center"
position="relative"
border="1px solid"
borderColor={borderColor}
borderRadius="16px"
w="100%"
py="16px"
px="14px"
>
<Image alt=" " src={SidebarImage.src} maxW="27px" me="10px" />
<Flex direction="column" justify="center" w="100%">
<Text fontSize="sm" fontWeight={'700'} color="#120F43" mb="2x">
PRO Member
</Text>
<Text fontWeight={'500'} fontSize="sm" color="gray.500">
Unlimited plan active
</Text>
</Flex>
</Flex>
);
} else {
// -------------- Free User Card --------------
return (
<Flex
justify="center"
direction="column"
align="center"
position="relative"
border="1px solid"
borderColor={borderColor}
borderRadius="16px"
w="100%"
py="20px"
px="18px"
>
<Image alt=" " src={SidebarImage.src} maxW="54px" />
<Flex direction="column" mb="12px" w="100%" pt="16px">
<Text
fontSize="lg"
fontWeight={'700'}
color="#120F43"
mb="10px"
textAlign={'center'}
>
Upgrade to Unlimited
</Text>
<Text
textAlign={'center'}
fontWeight={'500'}
fontSize="sm"
color="gray.500"
mb="14px"
>
Generate premium Essays by upgrading to an unlimited plan!
</Text>
</Flex>
<Button
onClick={() => {
onOpen();
}}
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
mb="14px"
_hover={{
boxShadow: '0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg: 'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
>
Go unlimited for just $9
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay bg="rgba(0, 0, 0, 0.85)" />
<ModalContent
mx="8px"
bg="transparent"
boxShadow="unset"
maxW="unset"
w="unset"
>
<ModalBody p="0px" position={'relative'}>
<Flex>
<Image
display={{ base: 'none', md: 'block' }}
zIndex="98"
borderLeftRadius="16px"
src={modalImage.src}
w="340px"
alt=" "
/>
<Flex
bg="white"
borderLeftRadius={{ base: '16px', md: '0px' }}
borderRightRadius="16px"
direction={'column'}
px={{ base: '30px', md: '42px' }}
py="34px"
w={{ md: '412px', lg: '456px' }}
minW={{ md: '412px', lg: '456px' }}
>
<Text
fontSize="26px"
fontWeight={'800'}
color={textColor}
mb="12px"
>
Upgrade to Unlimited
</Text>
<Text
mb="24px"
fontWeight="500"
fontSize="md"
color="gray.500"
>
Get access to all features and generate premium and
exclusive essays with our unlimited plan!
</Text>
{/* Features */}
<Flex w={{ base: '100%', xl: '80%' }} direction="column">
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Access to 12+ Essay types
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Up to 1500 words per Essay
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Citation formats (APA, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="20px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Academic Levels (Master, etc.)
</Text>
</Flex>
<Flex alignItems="center" mb="30px">
<Icon
me="10px"
w="20px"
h="20px"
color={'green.500'}
as={MdCheckCircle}
/>
<Text
as="span"
fontSize="sm"
fontWeight="600"
color={textColor}
letterSpacing="0px"
>
Essay Tones (Academic, etc.)
</Text>
</Flex>
</Flex>
{/* YEARLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTJ6R3RnzmIPX',
price: 'price_1P3gMyGx8VbJPRgzkoB6Fp8F'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTJ6R3RnzmIPX'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="14px"
px="14px"
cursor="pointer"
mb="20px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="8px"
>
Yearly
</Text>
<Badge
display={{
base: 'flex',
lg: 'none',
xl: 'flex'
}}
colorScheme="green"
borderRadius="4px"
color="green.500"
textTransform={'none'}
letterSpacing="0px"
px="0px"
w="max-content"
>
Save 35%
</Badge>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$5.75
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END YEARLY */}
{/* MONTHLY */}
<Flex
onClick={() =>
setPlan({
product: 'prod_PtTCPDFZbburMa',
price: 'price_1P3gGXGx8VbJPRgzdEZODy8K'
})
}
transition="0.15s linear"
align="center"
position="relative"
border="1px solid"
borderColor={
plan.product === 'prod_PtTCPDFZbburMa'
? 'brand.500'
: borderColor
}
borderRadius="10px"
w="100%"
py="16px"
px="14px"
cursor="pointer"
mb="28px"
>
<Text
fontSize="sm"
fontWeight={'700'}
color="#120F43"
mb="2x"
ms="8px"
me="4px"
>
Monthly
</Text>
<Text
display="flex"
ms="auto"
fontSize="md"
color={textColor}
letterSpacing="0px"
fontWeight="600"
lineHeight="100%"
>
$9
<Text
fontSize={'14px'}
color="gray.500"
fontWeight="500"
ms="4px"
as="span"
>
/month
</Text>
</Text>
</Flex>
{/* END MONTHLY */}
{products.map((product: any) => {
const price = product?.prices?.find(
(price: any) => price.id === plan.price
);
if (product.id === plan.product) {
if (!price) return null;
return (
<Button
key={product.id}
py="20px"
px="16px"
fontSize="sm"
variant="primary"
borderRadius="45px"
w={{ base: '100%' }}
h="54px"
mb="28px"
_hover={{
boxShadow:
'0px 21px 27px -10px rgba(96, 60, 255, 0.48) !important',
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%) !important',
_disabled: {
bg:
'linear-gradient(15.46deg, #4A25E1 26.3%, #7B5AFF 86.4%)'
}
}}
onClick={() => handleCheckout(price)}
>
Upgrade now
<Icon
as={MdChevronRight}
mt="2px"
h="16px"
w="16px"
/>
</Button>
);
}
})}
<Text
fontSize="xs"
color="gray.500"
fontWeight={'500'}
mx="auto"
mb="5px"
>
Used by 80,000+ users monthly
</Text>
<Flex direction="row" alignItems="center" mx="auto">
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="1px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Icon
me="6px"
w="16px"
h="16px"
color="orange.500"
as={IoIosStar}
/>
<Text
fontSize="sm"
fontWeight="800"
h="100%"
color={textColor}
>
4.9
</Text>
</Flex>
</Flex>
</Flex>
</ModalBody>
<ModalCloseButton
borderRadius="full"
color="#120F43"
bg="#F4F6FB !important"
_hover={{ bg: '#E9EDF6 !important' }}
_focus={{ bg: '#F4F6FB !important' }}
_active={{ bg: '#F4F6FB !important' }}
zIndex="99"
/>
</ModalContent>
</Modal>
<Text
textAlign={'center'}
fontWeight={'500'}
fontSize="xs"
color="gray.500"
>
Join 80,000+ users now
</Text>
</Flex>
);
}
}

View File

@@ -1,53 +0,0 @@
import { createContext } from 'react';
import type { Tables } from '@/types/types_db';
import { User } from '@supabase/supabase-js';
interface PlanContextType {
plan: {
product: string;
price: string;
};
setPlan: React.Dispatch<
React.SetStateAction<{
product: string;
price: string;
}>
>;
}
interface ApiKeyContextType {
apiKey: string;
setApiKey: React.Dispatch<React.SetStateAction<string>>;
}
interface OpenContextType {
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
}
type Subscription = Tables<'subscriptions'>;
type Product = Tables<'products'>;
type Price = Tables<'prices'>;
interface ProductWithPrices extends Product {
prices: Price[];
}
interface PriceWithProduct extends Price {
products: Product | null;
}
interface SubscriptionWithProduct extends Subscription {
prices: PriceWithProduct | null;
}
type UserDetails = { [x: string]: any } | null;
export const PlanContext = createContext<PlanContextType>(undefined);
export const ApiKeyContext = createContext<ApiKeyContextType>(undefined);
export const OpenContext = createContext<OpenContextType>(undefined);
export const ProductsContext = createContext<ProductWithPrices[] | undefined>(
undefined
);
export const SubscriptionContext = createContext<
SubscriptionWithProduct | any | null
>(undefined);
export const UserContext = createContext<User | undefined | null>(undefined);
export const UserDetailsContext = createContext<UserDetails | undefined | null>(
undefined
);

View File

@@ -1,85 +0,0 @@
{
"_meta": {
"template_version": 0
},
"fixtures": [
{
"name": "prod_hobby",
"path": "/v1/products",
"method": "post",
"params": {
"name": "Hobby",
"description": "Hobby product description"
}
},
{
"name": "price_hobby_month",
"path": "/v1/prices",
"method": "post",
"params": {
"product": "${prod_hobby:id}",
"currency": "usd",
"billing_scheme": "per_unit",
"unit_amount": 1000,
"recurring": {
"interval": "month",
"interval_count": 1
}
}
},
{
"name": "price_hobby_year",
"path": "/v1/prices",
"method": "post",
"params": {
"product": "${prod_hobby:id}",
"currency": "usd",
"billing_scheme": "per_unit",
"unit_amount": 10000,
"recurring": {
"interval": "year",
"interval_count": 1
}
}
},
{
"name": "prod_freelancer",
"path": "/v1/products",
"method": "post",
"params": {
"name": "Freelancer",
"description": "Freelancer product description"
}
},
{
"name": "price_freelancer_month",
"path": "/v1/prices",
"method": "post",
"params": {
"product": "${prod_freelancer:id}",
"currency": "usd",
"billing_scheme": "per_unit",
"unit_amount": 2000,
"recurring": {
"interval": "month",
"interval_count": 1
}
}
},
{
"name": "price_freelancer_year",
"path": "/v1/prices",
"method": "post",
"params": {
"product": "${prod_freelancer:id}",
"currency": "usd",
"billing_scheme": "per_unit",
"unit_amount": 20000,
"recurring": {
"interval": "year",
"interval_count": 1
}
}
}
]
}

View File

@@ -1,9 +0,0 @@
{
"compilerOptions": {
"jsx": "react",
"baseUrl": "src",
"paths": {
"*": ["src/*"]
}
}
}

View File

@@ -1,20 +0,0 @@
import { type NextRequest } from 'next/server';
import { updateSession } from '@/utils/supabase/middleware';
export async function middleware(request: NextRequest) {
return await updateSession(request);
}
export const config = {
matcher: [
/*
* Match all request paths except:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'
]
};

View File

@@ -1,21 +0,0 @@
const nextConfig = {
reactStrictMode: false, // changed this to false
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'lh3.googleusercontent.com',
port: '',
pathname: '/a/**'
},
{
protocol: 'https',
hostname: '*.googleusercontent.com',
port: '',
pathname: '**'
}
]
}
};
module.exports = nextConfig;

Some files were not shown because too many files have changed in this diff Show More