Update
This commit is contained in:
@@ -38,6 +38,7 @@ createInertiaApp({
|
||||
<AxiosProvider>
|
||||
<Toaster position="top-right" />
|
||||
<AuthDialog />
|
||||
|
||||
<App {...props} />
|
||||
</AxiosProvider>
|
||||
</MittProvider>
|
||||
|
||||
18
resources/js/modules/auth/auth-user.jsx
Normal file
18
resources/js/modules/auth/auth-user.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import useUserStore from '@/stores/UserStore';
|
||||
import { usePage } from '@inertiajs/react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const AuthUser = () => {
|
||||
const { auth } = usePage().props;
|
||||
const { user, fetchUser } = useUserStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (auth.user) {
|
||||
if (user == null) {
|
||||
fetchUser();
|
||||
}
|
||||
}
|
||||
}, [auth.user]);
|
||||
};
|
||||
|
||||
export default AuthUser;
|
||||
@@ -1,4 +1,6 @@
|
||||
// resources/js/Pages/User/Partials/upgrade-sheet.jsx
|
||||
import { usePage } from '@inertiajs/react';
|
||||
|
||||
import { SparklesText } from '@/components/magicui/sparkles-text';
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -8,11 +10,17 @@ import { useMitt } from '@/plugins/MittContext';
|
||||
import CartIcon from '@/reusables/cart-icon.jsx';
|
||||
import CoinIcon from '@/reusables/coin-icon.jsx';
|
||||
import usePricingStore from '@/stores/PricingStore.js';
|
||||
import useUserStore from '@/stores/UserStore.js';
|
||||
import { Download, ShieldIcon } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import UpgradePlanCarousel from './partials/upgrade-plan-carousel.tsx';
|
||||
|
||||
const UpgradeSheet = () => {
|
||||
const { subscription, one_times, isFetchingPricing, fetchPricing, isCheckingOut, checkoutSubscribe } = usePricingStore();
|
||||
const { plan, billing, user_usage } = useUserStore();
|
||||
const { auth } = usePage().props;
|
||||
|
||||
const [isRedirectingToBilling, setIsRedirectingToBilling] = useState(false);
|
||||
|
||||
// State to control sheet visibility
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -104,36 +112,108 @@ const UpgradeSheet = () => {
|
||||
</SheetHeader>
|
||||
|
||||
<div className="mx-auto w-full max-w-[600px] space-y-3 px-4">
|
||||
{subscription ? (
|
||||
<div id="plan-purchase" className="mx-auto space-y-6 rounded-lg border p-4 text-center sm:p-7">
|
||||
<SparklesText className="text-xl font-bold sm:text-2xl">
|
||||
Upgrade to {subscription?.name} Plan<br></br> at only {subscription?.symbol}
|
||||
{subscription?.amount}
|
||||
{subscription?.primary_interval === 'month' ? '/m' : '/y'}*
|
||||
</SparklesText>
|
||||
<UpgradePlanCarousel />
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
disabled={isCheckingOut}
|
||||
onClick={() => {
|
||||
handleSubscribe(subscription);
|
||||
}}
|
||||
size="lg"
|
||||
className="mx-auto w-[220px] text-sm sm:text-base"
|
||||
>
|
||||
{isCheckingOut ? (
|
||||
<Spinner className="text-muted h-4 w-4" />
|
||||
) : (
|
||||
<span>
|
||||
Subscribe at ({subscription?.symbol}
|
||||
{subscription?.amount}
|
||||
{subscription?.primary_interval === 'month' ? '/m' : '/y'})*
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
<div className="text-muted-foreground text-xs">* Launch pricing limited to first 1000 users</div>
|
||||
{auth?.user ? (
|
||||
<div id="stats">
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
{/* Non-watermark Exports */}
|
||||
{user_usage?.non_watermark_videos_left && (
|
||||
<div className="bg-card relative overflow-hidden rounded-xl border p-6 shadow-sm">
|
||||
<div className="relative z-10">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<Download className="text-primary h-5 w-5" />
|
||||
<span className="text-muted-foreground text-xs font-medium">Non-watermark Exports</span>
|
||||
</div>
|
||||
<div className="text-foreground text-xl font-bold">{user_usage?.non_watermark_videos_left}</div>
|
||||
<div className="text-muted-foreground text-sm">exports left</div>
|
||||
</div>
|
||||
<Download className="bg-muted absolute -top-2 -right-2 h-20 w-20 opacity-15" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Credits */}
|
||||
<div className="bg-card relative overflow-hidden rounded-xl border p-6 shadow-sm">
|
||||
<div className="relative z-10">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<CoinIcon className="text-primary h-5 w-5" />
|
||||
<span className="text-muted-foreground text-xs font-medium">Credits</span>
|
||||
</div>
|
||||
<div className="text-foreground text-xl font-bold">999</div>
|
||||
<div className="text-muted-foreground text-sm">available</div>
|
||||
</div>
|
||||
<CoinIcon className="bg-muted absolute -top-2 -right-2 h-20 w-20 opacity-15" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between rounded-lg border p-4">
|
||||
<div className="text-xs">Have an account with us?</div>
|
||||
<Button onClick={() => emitter.emit('login')} size="sm" variant="outline">
|
||||
Login Now
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{subscription ? (
|
||||
<>
|
||||
{auth.user && plan.tier != 'free' ? (
|
||||
<div className="mx-auto space-y-6 rounded-lg border p-4 text-center sm:p-7">
|
||||
<SparklesText className="text-xl font-bold sm:text-2xl">You're now in the {plan?.name} plan!</SparklesText>
|
||||
|
||||
{billing?.portal && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
setIsRedirectingToBilling(true);
|
||||
window.location.replace(billing?.portal);
|
||||
}}
|
||||
disabled={isRedirectingToBilling}
|
||||
>
|
||||
{isRedirectingToBilling ? <Spinner className="text-muted-foreground h-4 w-4" /> : 'Manage Subscription'}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="text-muted-foreground block rounded border p-3 text-center text-xs">
|
||||
<ShieldIcon className="mr-1 mb-1 inline h-4 w-4" />
|
||||
All our payments are securely processed by Stripe.
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div id="plan-purchase" className="mx-auto space-y-6 rounded-lg border p-4 text-center sm:p-7">
|
||||
<SparklesText className="text-xl font-bold sm:text-2xl">
|
||||
Upgrade to {subscription?.name} Plan<br></br> at only {subscription?.symbol}
|
||||
{subscription?.amount}
|
||||
{subscription?.primary_interval === 'month' ? '/m' : '/y'}*
|
||||
</SparklesText>
|
||||
<UpgradePlanCarousel />
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
disabled={isCheckingOut}
|
||||
onClick={() => {
|
||||
handleSubscribe(subscription);
|
||||
}}
|
||||
size="lg"
|
||||
className="mx-auto w-[220px] text-sm sm:text-base"
|
||||
>
|
||||
{isCheckingOut ? (
|
||||
<Spinner className="text-muted h-4 w-4" />
|
||||
) : (
|
||||
<span>
|
||||
Subscribe at ({subscription?.symbol}
|
||||
{subscription?.amount}
|
||||
{subscription?.primary_interval === 'month' ? '/m' : '/y'})*
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
<div className="text-muted-foreground text-xs">* Launch pricing limited to first 1000 users</div>
|
||||
|
||||
<div className="text-muted-foreground block rounded border p-3 text-center text-xs">
|
||||
<ShieldIcon className="mr-1 mb-1 inline h-4 w-4" />
|
||||
All our payments are securely processed by Stripe.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
isFetchingPricing && (
|
||||
<div className="mx-auto w-full">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AuthUser from '@/modules/auth/auth-user';
|
||||
import Editor from '@/modules/editor/editor.jsx';
|
||||
import FlashMessages from '@/modules/flash/flash-messages';
|
||||
|
||||
@@ -6,6 +7,7 @@ const Home = () => {
|
||||
<div className="min-h-screen bg-neutral-50 dark:bg-neutral-800">
|
||||
<Editor />
|
||||
<FlashMessages />
|
||||
<AuthUser />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
50
resources/js/stores/UserStore.js
Normal file
50
resources/js/stores/UserStore.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import axiosInstance from '@/plugins/axios-plugin';
|
||||
import { mountStoreDevtool } from 'simple-zustand-devtools';
|
||||
import { route } from 'ziggy-js';
|
||||
import { create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
|
||||
const useUserStore = create(
|
||||
devtools((set, get) => ({
|
||||
// Pricing Plans
|
||||
user: null,
|
||||
user_usage: null,
|
||||
plan: {
|
||||
name: 'Free',
|
||||
tier: 'free',
|
||||
},
|
||||
billing: null,
|
||||
|
||||
isLoadingUser: false,
|
||||
|
||||
// Fetch backgrounds
|
||||
fetchUser: async () => {
|
||||
set({ isLoadingUser: true });
|
||||
try {
|
||||
const response = await axiosInstance.post(route('api.user'));
|
||||
set({
|
||||
user: response.data.success.data.user,
|
||||
user_usage: response.data.success.data.user.user_usage,
|
||||
plan: response.data.success.data.user.plan,
|
||||
billing: response.data.success.data.billing,
|
||||
});
|
||||
//return response.data.success.data;
|
||||
} catch (error) {
|
||||
console.error(route('api.user'));
|
||||
console.error('Error fetching:', error);
|
||||
} finally {
|
||||
set({ isLoadingUser: false });
|
||||
}
|
||||
},
|
||||
})),
|
||||
{
|
||||
name: 'UserStore',
|
||||
store: 'UserStore',
|
||||
},
|
||||
);
|
||||
|
||||
if (import.meta.env.APP_ENV === 'local') {
|
||||
mountStoreDevtool('UserStore', useUserStore);
|
||||
}
|
||||
|
||||
export default useUserStore;
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user