mirror of
https://github.com/fergalmoran/supanextail.git
synced 2025-12-22 09:17:54 +00:00
Handle sub in dashboard
This commit is contained in:
@@ -4,49 +4,18 @@ You can add as many elements as you want. Don't forget to update your getProfile
|
||||
function with your new elements.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Avatar from "./Avatar";
|
||||
import { PriceIds } from "utils/priceList";
|
||||
import { supabase } from "../utils/supabaseClient";
|
||||
import { toast } from "react-toastify";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function Account({ session }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [username, setUsername] = useState(null);
|
||||
const [website, setWebsite] = useState(null);
|
||||
export default function Account(props) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [username, setUsername] = useState(props.profile.username);
|
||||
const [website, setWebsite] = useState(props.profile.website);
|
||||
const [avatar_url, setAvatarUrl] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getProfile();
|
||||
}, [session]);
|
||||
|
||||
async function getProfile() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const user = supabase.auth.user();
|
||||
|
||||
let { data, error, status } = await supabase
|
||||
.from("profiles")
|
||||
.select(`username, website, avatar_url`)
|
||||
.eq("id", user.id)
|
||||
.single();
|
||||
|
||||
if (error && status !== 406) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
setUsername(data.username);
|
||||
setWebsite(data.website);
|
||||
setAvatarUrl(data.avatar_url);
|
||||
}
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateProfile({ username, website, avatar_url }) {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -71,64 +40,71 @@ export default function Account({ session }) {
|
||||
alert(error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
toast.success("Your profile has been updated")
|
||||
toast.success("Your profile has been updated");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='form-widget mt-10 flex flex-col text-left'>
|
||||
<Avatar
|
||||
url={avatar_url}
|
||||
size={150}
|
||||
onUpload={(url) => {
|
||||
setAvatarUrl(url);
|
||||
updateProfile({ username, website, avatar_url: url });
|
||||
}}
|
||||
/>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='email' className='my-auto text-sm mb-2'>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='email'
|
||||
type='text'
|
||||
value={session.user.email}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='username' className='my-auto text-sm mb-2'>
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='username'
|
||||
type='text'
|
||||
value={username || ""}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='website' className='my-auto text-sm mb-2'>
|
||||
Website
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='website'
|
||||
type='website'
|
||||
value={website || ""}
|
||||
onChange={(e) => setWebsite(e.target.value)}
|
||||
<div className='flex flex-col text-left w-full'>
|
||||
<div className='max-w-sm flex flex-col justify-center m-auto w-full p-5'>
|
||||
<Avatar
|
||||
url={avatar_url}
|
||||
size={150}
|
||||
onUpload={(url) => {
|
||||
setAvatarUrl(url);
|
||||
updateProfile({ username, website, avatar_url: url });
|
||||
}}
|
||||
/>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='email' className='my-auto text-sm mb-2'>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='email'
|
||||
type='text'
|
||||
value={props.session.user.email}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='username' className='my-auto text-sm mb-2'>
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='username'
|
||||
type='text'
|
||||
value={username || ""}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-5 flex flex-col'>
|
||||
<label htmlFor='website' className='my-auto text-sm mb-2'>
|
||||
Website
|
||||
</label>
|
||||
<input
|
||||
className='input input-primary input-bordered input-sm flex-1'
|
||||
id='website'
|
||||
type='website'
|
||||
value={website || ""}
|
||||
onChange={(e) => setWebsite(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='m-auto'>
|
||||
<button
|
||||
className='btn btn-primary btn-sm'
|
||||
onClick={() => updateProfile({ username, website, avatar_url })}
|
||||
disabled={loading}>
|
||||
{loading ? "Loading ..." : "Update My Profile"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='m-auto'>
|
||||
<button
|
||||
className='btn btn-primary btn-sm'
|
||||
onClick={() => updateProfile({ username, website, avatar_url })}
|
||||
disabled={loading}>
|
||||
{loading ? "Loading ..." : "Update My Profile"}
|
||||
</button>
|
||||
<div className='max-w-xl flex flex-col justify-center m-auto w-full p-5 bordered border-2 border-primary shadow-lg my-5'>
|
||||
<h2>Your current plan</h2>
|
||||
<p>{props.plan.plan ? PriceIds[props.plan.plan] : "Free tier"}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ You can switch between flat payment or subscription by setting the flat variable
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { Auth } from "@supabase/ui";
|
||||
import { Prices } from "utils/priceList";
|
||||
import { Switch } from "@headlessui/react";
|
||||
import axios from "axios";
|
||||
import getStripe from "utils/stripe";
|
||||
@@ -32,20 +33,7 @@ const Pricing = () => {
|
||||
);
|
||||
}
|
||||
}, [user]);
|
||||
const prices = {
|
||||
personal: {
|
||||
monthly: "price_1J5q2yDMjD0UnVmMXzEWYDnl",
|
||||
anually: "price_1J5q45DMjD0UnVmMQxXHKGAv",
|
||||
},
|
||||
team: {
|
||||
monthly: "price_1J5q3GDMjD0UnVmMlHc5Eedq",
|
||||
anually: "price_1J5q8zDMjD0UnVmMqsngM91X",
|
||||
},
|
||||
pro: {
|
||||
monthly: "price_1J5q3TDMjD0UnVmMJKX3nkDq",
|
||||
anually: "price_1J5q9VDMjD0UnVmMIQtVDSZ9",
|
||||
},
|
||||
};
|
||||
|
||||
const flat = false; // Switch between subscription system or flat prices
|
||||
const pricing = {
|
||||
monthly: {
|
||||
@@ -165,7 +153,9 @@ const Pricing = () => {
|
||||
onClick={(e) =>
|
||||
handleSubmit(
|
||||
e,
|
||||
enabled ? prices.personal.anually : prices.personal.monthly
|
||||
enabled
|
||||
? Prices.personal.anually.id
|
||||
: Prices.personal.monthly.id
|
||||
)
|
||||
}>
|
||||
Buy Now
|
||||
@@ -206,7 +196,9 @@ const Pricing = () => {
|
||||
onClick={(e) =>
|
||||
handleSubmit(
|
||||
e,
|
||||
enabled ? prices.team.anually : prices.team.monthly
|
||||
enabled
|
||||
? Prices.team.anually.id
|
||||
: Prices.team.monthly.id
|
||||
)
|
||||
}>
|
||||
Buy Now
|
||||
@@ -247,7 +239,9 @@ const Pricing = () => {
|
||||
onClick={(e) =>
|
||||
handleSubmit(
|
||||
e,
|
||||
enabled ? prices.pro.anually : prices.pro.monthly
|
||||
enabled
|
||||
? Prices.pro.anually.id
|
||||
: Prices.pro.monthly.id
|
||||
)
|
||||
}>
|
||||
Buy Now
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { getSub, supabase } from "../utils/supabaseClient";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Auth from "../components/Auth";
|
||||
import Dashboard from "../components/Dashboard";
|
||||
import Head from "next/head";
|
||||
import Layout from "components/Layout";
|
||||
import { supabase } from "../utils/supabaseClient";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const DashboardPage = ({ user }) => {
|
||||
const DashboardPage = ({ user, plan, profile }) => {
|
||||
const [session, setSession] = useState(null);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -33,7 +34,7 @@ const DashboardPage = ({ user }) => {
|
||||
</Head>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
<>
|
||||
<h1 className='text-4xl font-bold md:text-5xl font-title'>
|
||||
Dashboard
|
||||
</h1>
|
||||
@@ -44,20 +45,42 @@ const DashboardPage = ({ user }) => {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Dashboard key={user.id} session={session} />
|
||||
<Dashboard
|
||||
key={user.id}
|
||||
session={session}
|
||||
plan={plan}
|
||||
profile={profile}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export async function getServerSideProps({ req }) {
|
||||
const { user } = await supabase.auth.api.getUserByCookie(req);
|
||||
const supabaseAdmin = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.SUPABASE_ADMIN_KEY
|
||||
);
|
||||
const { user } = await supabaseAdmin.auth.api.getUserByCookie(req);
|
||||
|
||||
// If the user exist, you will retrieve the user profile and if he/she's a paid user
|
||||
if (user) {
|
||||
return { props: { user } };
|
||||
let { data: plan, error } = await supabaseAdmin
|
||||
.from("subscriptions")
|
||||
.select("paid_user, plan")
|
||||
.eq("id", user.id)
|
||||
.single();
|
||||
|
||||
let { data: profile, errorprofile } = await supabaseAdmin
|
||||
.from("profiles")
|
||||
.select(`username, website, avatar_url`)
|
||||
.eq("id", user.id)
|
||||
.single();
|
||||
|
||||
return { props: { user, plan, profile } };
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
|
||||
35
public/logopremium.svg
Normal file
35
public/logopremium.svg
Normal file
@@ -0,0 +1,35 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="264.263" height="59.7" viewBox="0 0 264.263 59.7">
|
||||
<g id="Groupe_14" data-name="Groupe 14" transform="translate(-6.737 -96.3)">
|
||||
<g id="Groupe_13" data-name="Groupe 13" transform="translate(7.437 -99.899)">
|
||||
<g id="Groupe_2" data-name="Groupe 2" transform="translate(72.056 206.798)">
|
||||
<g id="Groupe_1" data-name="Groupe 1" transform="translate(0 0)">
|
||||
<text id="SupaNexTail" transform="translate(-0.493 30.101)" fill="#a8a1a1" font-size="29" font-family="Poppins-ExtraBold, Poppins" font-weight="800"><tspan x="0" y="0">Supa</tspan><tspan y="0" fill="#37cdbe">Nex</tspan><tspan y="0">Tail</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Groupe_4" data-name="Groupe 4" transform="translate(0 196.899)">
|
||||
<path id="Tracé_25" data-name="Tracé 25" d="M31.262,117.215c0,.8,9.054,1.456,20.222,1.456s20.222-.652,20.222-1.456-9.054-1.456-20.222-1.456-20.222.652-20.222,1.456Z" transform="translate(-25.89 -59.671)" fill="#45413c" opacity="0.15"/>
|
||||
<path id="Tracé_26" data-name="Tracé 26" d="M70.055,53.76H30.106a1.78,1.78,0,0,0-1.781,1.78V81.385h43.51V55.543a1.78,1.78,0,0,0-1.78-1.783Z" transform="translate(-24.486 -30.037)" fill="#fff"/>
|
||||
<path id="Tracé_27" data-name="Tracé 27" d="M71.835,71.3a7.5,7.5,0,0,0-10.108.483,4.386,4.386,0,0,0-1.264-.185,4.483,4.483,0,0,0-4.268,3.13,5.214,5.214,0,0,0-2.68,1.408,6.358,6.358,0,0,1-.69-2.695c1.784-3.3,3.663-7.351,3.664-9.768a14.682,14.682,0,0,0-.255-2.639l.127.137a2.53,2.53,0,0,0,4.166-.658,9.4,9.4,0,0,0,.531-6.745H39.106a9.408,9.408,0,0,0,.531,6.746,2.532,2.532,0,0,0,4.166.658l.128-.139a14.636,14.636,0,0,0-.255,2.636c0,2.418,1.879,6.472,3.663,9.776a6.358,6.358,0,0,1-.691,2.687,5.205,5.205,0,0,0-2.681-1.405A4.484,4.484,0,0,0,39.7,71.6a4.385,4.385,0,0,0-1.264.184A7.5,7.5,0,0,0,28.325,71.3V81.39h43.51Z" transform="translate(-24.486 -30.041)" fill="#e0e0e0"/>
|
||||
<path id="Tracé_28" data-name="Tracé 28" d="M70.055,53.76H30.106a1.78,1.78,0,0,0-1.781,1.78V81.385h43.51V55.543a1.78,1.78,0,0,0-1.78-1.783Z" transform="translate(-24.486 -30.037)" fill="rgba(0,0,0,0)" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_29" data-name="Tracé 29" d="M71.576,59.648H34.251L34.209,84.2H71.576Z" transform="translate(-27.298 -32.851)" fill="#00b8f0"/>
|
||||
<path id="Tracé_30" data-name="Tracé 30" d="M62.32,59.648,35.958,84.2H34.209l.042-24.552H62.32Z" transform="translate(-27.298 -32.851)" fill="#4acfff"/>
|
||||
<path id="Tracé_31" data-name="Tracé 31" d="M69.86,72.384a7.486,7.486,0,0,0-5.32,2.211,4.384,4.384,0,0,0-1.264-.185,4.483,4.483,0,0,0-4.268,3.13,5.215,5.215,0,0,0-2.68,1.408,6.358,6.358,0,0,1-.69-2.695c1.784-3.3,3.663-7.351,3.664-9.768a14.681,14.681,0,0,0-.255-2.639l.127.137a2.53,2.53,0,0,0,4.166-.658,10.576,10.576,0,0,0,.932-3.674H41.518a10.569,10.569,0,0,0,.932,3.675,2.532,2.532,0,0,0,4.166.658l.128-.139a14.635,14.635,0,0,0-.255,2.636c0,2.418,1.879,6.472,3.663,9.776a6.358,6.358,0,0,1-.691,2.687A5.2,5.2,0,0,0,46.78,77.54a4.484,4.484,0,0,0-4.27-3.132,4.385,4.385,0,0,0-1.264.184,7.519,7.519,0,0,0-7.016-2.017L34.209,84.2H71.576V72.582A7.512,7.512,0,0,0,69.86,72.384Z" transform="translate(-27.298 -32.853)" fill="#009fd9"/>
|
||||
<path id="Tracé_32" data-name="Tracé 32" d="M71.576,59.648H34.251L34.209,84.2H71.576Z" transform="translate(-27.298 -32.851)" fill="rgba(244,253,0,0.33)" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_33" data-name="Tracé 33" d="M72.16,109.749H20.971V107.57a.89.89,0,0,1,.892-.89h49.4a.89.89,0,0,1,.891.89Z" transform="translate(-20.971 -55.331)" fill="#f0f0f0" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_34" data-name="Tracé 34" d="M72.162,112.56a53.227,53.227,0,0,1-14.617,2.046H35.593a53.226,53.226,0,0,1-14.616-2.046Z" transform="translate(-20.973 -58.142)" fill="#bdbec0" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_35" data-name="Tracé 35" d="M66.1,87.274A5.815,5.815,0,0,0,61.232,89.9a2.771,2.771,0,0,0-4.5,2.18c0,.365.175.254-.506.254A3.539,3.539,0,0,0,52.8,95.019c-.81-1.013-2.651-1.839-2.651-6.732h-2.03c0,4.879-1.84,5.719-2.651,6.732a3.539,3.539,0,0,0-3.425-2.681c-.681,0-.506.109-.506-.254a2.771,2.771,0,0,0-4.5-2.179,5.821,5.821,0,1,0-8.783,7.5h41.76A5.818,5.818,0,0,0,66.1,87.274Z" transform="translate(-23.539 -46.054)" fill="#e8f4fa"/>
|
||||
<path id="Tracé_36" data-name="Tracé 36" d="M32.166,89.806a5.815,5.815,0,0,1,4.869,2.631,2.771,2.771,0,0,1,4.5,2.18c0,.365-.175.254.506.254A3.529,3.529,0,0,1,45.418,97.4h.188c.951-.957,3.527-1.944,3.527-6.584,0,4.654,2.576,5.627,3.527,6.584h.188a3.529,3.529,0,0,1,3.374-2.532c.682,0,.506.109.506-.254a2.771,2.771,0,0,1,4.5-2.179,5.82,5.82,0,0,1,10.552,1.93,5.823,5.823,0,0,0-10.552-4.462,2.771,2.771,0,0,0-4.5,2.179c0,.365.175.254-.506.254A3.539,3.539,0,0,0,52.8,95.019c-.81-1.014-2.651-1.839-2.651-6.732H48.12c0,4.879-1.84,5.719-2.651,6.732a3.539,3.539,0,0,0-3.425-2.681c-.682,0-.506.109-.506-.254a2.771,2.771,0,0,0-4.5-2.179,5.822,5.822,0,0,0-10.552,4.462,5.824,5.824,0,0,1,5.681-4.562Z" transform="translate(-23.538 -46.054)" fill="#fff"/>
|
||||
<path id="Tracé_37" data-name="Tracé 37" d="M66.1,87.274A5.815,5.815,0,0,0,61.232,89.9a2.771,2.771,0,0,0-4.5,2.18c0,.365.175.254-.506.254A3.539,3.539,0,0,0,52.8,95.019c-.81-1.013-2.651-1.839-2.651-6.732h-2.03c0,4.879-1.84,5.719-2.651,6.732a3.539,3.539,0,0,0-3.425-2.681c-.681,0-.506.109-.506-.254a2.771,2.771,0,0,0-4.5-2.179,5.821,5.821,0,1,0-8.783,7.5h41.76A5.818,5.818,0,0,0,66.1,87.274Z" transform="translate(-23.539 -46.054)" fill="rgba(0,0,0,0)" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_38" data-name="Tracé 38" d="M47.648,96.765a3.546,3.546,0,0,1,3.206-2.027m-6.079-.254a2.781,2.781,0,0,1,1.063-2.192m22.4,4.473a3.546,3.546,0,0,0-3.206-2.027m6.079-.254a2.777,2.777,0,0,0-1.063-2.192" transform="translate(-32.348 -48.454)" fill="rgba(0,0,0,0)" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_39" data-name="Tracé 39" d="M68.827,60.116h-6.29a17.681,17.681,0,0,0-1.573,6.59c0,2.488,2.688,7.608,4,9.966a.854.854,0,0,0,1.419,0C67.7,74.314,70.4,69.2,70.4,66.707A17.682,17.682,0,0,0,68.827,60.116Z" transform="translate(-40.087 -33.075)" fill="#ffaa54" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_40" data-name="Tracé 40" d="M69.29,60.115s1.963,4.391-.084,7.662a.884.884,0,0,1-1.408,0c-2.046-3.273-.081-7.663-.081-7.663Z" transform="translate(-42.908 -33.074)" fill="#ffe500" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_41" data-name="Tracé 41" d="M70.506,18.769A8.732,8.732,0,0,0,68.291,12L65.6,9.031a2.184,2.184,0,0,0-3.235,0L59.667,12a8.732,8.732,0,0,0-2.217,6.768l1.723,16.59h9.611Z" transform="translate(-38.384 -8.315)" fill="#fff" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_42" data-name="Tracé 42" d="M56.3,53.87l-2.716,2.948a.843.843,0,0,1-1.389-.219c-.941-2.055-2.154-6.572,3.4-9.549Zm9.609,0,2.716,2.948A.843.843,0,0,0,70.01,56.6c.941-2.055,2.154-6.572-3.4-9.549ZM55.781,48.9l.516,4.97h9.609l.516-4.97H55.781Z" transform="translate(-35.507 -26.829)" fill="#ff6242" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
<path id="Tracé_43" data-name="Tracé 43" d="M64.459,23.923a2.893,2.893,0,1,0,2.893-2.893A2.893,2.893,0,0,0,64.459,23.923Z" transform="translate(-41.757 -14.393)" fill="#00b8f0"/>
|
||||
<path id="Tracé_44" data-name="Tracé 44" d="M65.3,25.966A2.894,2.894,0,0,1,69.4,21.873Z" transform="translate(-41.756 -14.39)" fill="#4acfff"/>
|
||||
<path id="Tracé_45" data-name="Tracé 45" d="M64.459,23.923a2.893,2.893,0,1,0,2.893-2.893A2.893,2.893,0,0,0,64.459,23.923Zm2.893,10.688V45.248" transform="translate(-41.757 -14.393)" fill="rgba(0,0,0,0)" stroke="#45413c" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
||||
</g>
|
||||
</g>
|
||||
<text id="Premium" transform="translate(234 151)" fill="#f8dd4b" font-size="15" font-family="Poppins-ExtraBold, Poppins" font-weight="800"><tspan x="-36.202" y="0">Premium</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
45
utils/priceList.js
Normal file
45
utils/priceList.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// You can store your price IDs from Stripe here
|
||||
|
||||
const Prices = {
|
||||
personal: {
|
||||
monthly: {
|
||||
id: "price_1J5q2yDMjD0UnVmMXzEWYDnl",
|
||||
desc: "Personal plan (monthly)",
|
||||
},
|
||||
anually: {
|
||||
id: "price_1J5q45DMjD0UnVmMQxXHKGAv",
|
||||
desc: "Personal plan (anually)",
|
||||
},
|
||||
},
|
||||
team: {
|
||||
monthly: {
|
||||
id: "price_1J5q3GDMjD0UnVmMlHc5Eedq",
|
||||
desc: "Team plan (monthly)",
|
||||
},
|
||||
anually: {
|
||||
id: "price_1J5q8zDMjD0UnVmMqsngM91X",
|
||||
desc: "Team plan (anually)",
|
||||
},
|
||||
},
|
||||
pro: {
|
||||
monthly: {
|
||||
id: "price_1J5q3TDMjD0UnVmMJKX3nkDq",
|
||||
desc: "Pro plan (monthly)",
|
||||
},
|
||||
anually: {
|
||||
id: "price_1J5q9VDMjD0UnVmMIQtVDSZ9",
|
||||
desc: "Pro plan (anually)",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const PriceIds = {
|
||||
price_1J5q2yDMjD0UnVmMXzEWYDnl: "Personal plan (monthly)",
|
||||
price_1J5q45DMjD0UnVmMQxXHKGAv: "Personal plan (anually)",
|
||||
price_1J5q3GDMjD0UnVmMlHc5Eedq: "Team plan (monthly)",
|
||||
price_1J5q8zDMjD0UnVmMqsngM91X: "Team plan (anually)",
|
||||
price_1J5q3TDMjD0UnVmMJKX3nkDq: "Pro plan (monthly)",
|
||||
price_1J5q9VDMjD0UnVmMIQtVDSZ9: "Pro plan (anually)",
|
||||
};
|
||||
|
||||
export { Prices, PriceIds };
|
||||
@@ -1,6 +1,16 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
||||
|
||||
// Check if a user has a paid plan
|
||||
export const getSub = async () => {
|
||||
let { data: subscriptions, error } = await supabase
|
||||
.from("subscriptions")
|
||||
.select("paid_user, plan");
|
||||
if (subscriptions) {
|
||||
return subscriptions;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user