Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev to prod #1169

Merged
merged 4 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const AddDestination = ({ organization }: { organization: Organization }) => {
<CardContent>
<div className="flex items-center gap-4 w-fit">
<YoutubeConnectButton state={state} />
<TwitterConnectButton state={state} />
{/* <TwitterConnectButton state={state} /> */}
</div>
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const EditSession = async ({ params, searchParams }: studioPageParams) => {
<div className="flex flex-col space-y-2">
<Label>Publish to Socials</Label>
<div className="flex flex-row gap-2">
<UploadToYoutubeButton
{/* <UploadToYoutubeButton
organization={organization}
organizationSlug={params.organization}
sessionId={session._id}
Expand All @@ -104,7 +104,7 @@ const EditSession = async ({ params, searchParams }: studioPageParams) => {
organization={organization}
organizationSlug={params.organization}
sessionId={session._id}
/>
/> */}
</div>
</div>
</div>
Expand Down
35 changes: 22 additions & 13 deletions packages/app/app/studio/[organization]/(root)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ export default async function OrganizationPage({

if (!organization) return notFound();

const hasFeatures = isFeatureAvailable(
organization.expirationDate,
organization.currentStages,
organization.paidStages
);
const hasValidSubscription = isFeatureAvailable(organization.expirationDate);
const hasReachedStageLimit = (organization.currentStages ?? 0) >= (organization.paidStages ?? 0);

// Calculate the start of the current day
const startOfDay = new Date();
Expand All @@ -39,12 +36,24 @@ export default async function OrganizationPage({
<div className="flex w-full flex-col p-2">
<h2 className="text-lg font-bold">Create</h2>
<div className="flex items-center gap-4 p-4">
{hasFeatures ? (
<CreateLivestreamModal
variant="primary"
show={searchParams?.show}
organization={organization}
/>
{hasValidSubscription ? (
hasReachedStageLimit ? (
<FeatureButton
organizationId={organization._id.toString()}
variant="primary"
className="flex items-center gap-2"
forceLockedState={true}
>
<Radio className="w-5 h-5" />
Create Livestream
</FeatureButton>
) : (
<CreateLivestreamModal
variant="primary"
show={searchParams?.show}
organization={organization}
/>
)
) : (
<FeatureButton
organizationId={organization._id.toString()}
Expand All @@ -56,7 +65,7 @@ export default async function OrganizationPage({
</FeatureButton>
)}

{hasFeatures ? (
{hasValidSubscription ? (
<UploadVideoDialog organizationId={organization._id.toString()} />
) : (
<FeatureButton
Expand All @@ -69,7 +78,7 @@ export default async function OrganizationPage({
</FeatureButton>
)}

{hasFeatures ? (
{hasValidSubscription ? (
<Link
href={`/studio/${organization.slug}/library?layout=list&page=1&limit=20&clipable=true`}
>
Expand Down
31 changes: 20 additions & 11 deletions packages/app/components/Layout/NavbarStudio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,8 @@ const NavbarStudio = ({
return notFound();
}

const hasFeatures = isFeatureAvailable(
organization.expirationDate,
organization.currentStages,
organization.paidStages
);
const hasValidSubscription = isFeatureAvailable(organization.expirationDate);
const hasReachedStageLimit = (organization.currentStages ?? 0) >= (organization.paidStages ?? 0);

return (
<NavigationMenu className="h-[72px] w-full sticky top-0 flex items-center p-2 px-4 bg-white md:hidden lg:flex z-[30]">
Expand All @@ -54,11 +51,23 @@ const NavbarStudio = ({
/>
</div>
<div className="flex items-center justify-end space-x-2">
{hasFeatures ? (
<CreateLivestreamModal
variant="outline"
organization={organization}
/>
{hasValidSubscription ? (
hasReachedStageLimit ? (
<FeatureButton
organizationId={organization._id.toString()}
variant="outline"
className="flex items-center gap-2"
forceLockedState={true}
>
<Radio className="w-5 h-5" />
Create Livestream
</FeatureButton>
) : (
<CreateLivestreamModal
variant="outline"
organization={organization}
/>
)
) : (
<FeatureButton
organizationId={organization._id.toString()}
Expand All @@ -69,7 +78,7 @@ const NavbarStudio = ({
Create Livestream
</FeatureButton>
)}
{hasFeatures ? (
{hasValidSubscription ? (
<UploadVideoDialog organizationId={organization._id.toString()} />
) : (
<FeatureButton
Expand Down
10 changes: 7 additions & 3 deletions packages/app/components/ui/feature-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface FeatureButtonProps {
size?: 'default' | 'sm' | 'lg' | 'icon';
loading?: boolean;
type?: 'button' | 'submit' | 'reset';
forceLockedState?: boolean;
}

const FeatureButton = ({
Expand All @@ -38,13 +39,14 @@ const FeatureButton = ({
size = 'default',
loading,
type = 'button',
forceLockedState = false,
}: FeatureButtonProps) => {
const router = useRouter();
const { canUseFeatures, isLoading, organizationSlug } =
useSubscription(organizationId);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
if (!canUseFeatures) {
if (!canUseFeatures || forceLockedState) {
event.preventDefault();
event.stopPropagation();
router.push(`/studio/${organizationSlug}/payments`);
Expand All @@ -53,17 +55,19 @@ const FeatureButton = ({
onClick?.();
};

const isLocked = !canUseFeatures || forceLockedState;

return (
<Button
variant={variant}
className={cn(className, 'relative', !canUseFeatures && 'opacity-60')}
className={cn(className, 'relative', isLocked && 'opacity-60')}
onClick={handleClick}
disabled={disabled || isLoading}
size={size}
type={type}
loading={loading}
>
{!canUseFeatures && !loading && <Lock className="w-4 h-4 mr-2" />}
{isLocked && !loading && <Lock className="w-4 h-4 mr-2" />}
{children}
</Button>
);
Expand Down
12 changes: 11 additions & 1 deletion packages/app/lib/hooks/useSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface SubscriptionStatus {
isProcessing: boolean;
isPending: boolean;
isFailed: boolean;
hasAvailableStages: boolean;
}

export const useSubscription = (organizationId: string) => {
Expand All @@ -17,6 +18,7 @@ export const useSubscription = (organizationId: string) => {
if (loading || error || !organization) {
return {
canUseFeatures: false,
canCreateStages: false,
isLoading: loading,
error,
organizationSlug: '',
Expand All @@ -27,6 +29,7 @@ export const useSubscription = (organizationId: string) => {
isProcessing: false,
isPending: false,
isFailed: false,
hasAvailableStages: false
} as SubscriptionStatus,
};
}
Expand All @@ -38,6 +41,9 @@ export const useSubscription = (organizationId: string) => {
isFailed: organization.paymentStatus === 'failed',
daysLeft: 0,
hasExpired: true,
hasAvailableStages: typeof organization.currentStages === 'undefined' ||
typeof organization.paidStages === 'undefined' ||
organization.currentStages < organization.paidStages
};

if (organization.expirationDate) {
Expand All @@ -49,11 +55,15 @@ export const useSubscription = (organizationId: string) => {
status.hasExpired = status.daysLeft <= 0;
}

// Can use features if subscription is active and not expired
// Base feature access - only checks subscription status and expiry
const canUseFeatures = status.isActive && !status.hasExpired;

// Stage creation - checks subscription, expiry AND stage limits
const canCreateStages = canUseFeatures && status.hasAvailableStages;

return {
canUseFeatures,
canCreateStages,
isLoading: loading,
error,
organizationSlug: organization.slug || '',
Expand Down
6 changes: 1 addition & 5 deletions packages/app/lib/services/organizationService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ export async function fetchOrganization({
const response = await fetch(
`${apiUrl()}/organizations/${
organizationId ? organizationId : organizationSlug
}`,
{
cache: 'no-store',
next: { revalidate: 0 },
}
}`
);
const data = (await response.json()).data;

Expand Down
14 changes: 2 additions & 12 deletions packages/app/lib/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,8 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

export const isFeatureAvailable = (
expirationDate: Date | null | undefined,
currentStages?: number,
paidStages?: number
) => {
const hasValidSubscription =
expirationDate && new Date(expirationDate).getTime() > new Date().getTime();
const hasAvailableStages =
typeof currentStages === 'undefined' ||
typeof paidStages === 'undefined' ||
currentStages < paidStages;
return hasValidSubscription && hasAvailableStages;
export const isFeatureAvailable = (expirationDate: Date | null | undefined) => {
return expirationDate && new Date(expirationDate).getTime() > new Date().getTime();
};

export const selectOptionFocusHandle = (
Expand Down
Loading