Skip to content
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
2 changes: 2 additions & 0 deletions apps/sim/app/(landing)/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
sizes='(max-width: 768px) 100vw, 450px'
priority
itemProp='image'
unoptimized
/>
</div>
</div>
Expand Down Expand Up @@ -143,6 +144,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
className='h-[160px] w-full object-cover'
sizes='(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw'
loading='lazy'
unoptimized
/>
<div className='p-3'>
<div className='mb-1 text-[#999] text-xs'>
Expand Down
1 change: 1 addition & 0 deletions apps/sim/app/(landing)/blog/authors/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
width={600}
height={315}
className='h-[160px] w-full object-cover transition-transform group-hover:scale-[1.02]'
unoptimized
/>
<div className='p-3'>
<div className='mb-1 text-[#999] text-xs'>
Expand Down
1 change: 1 addition & 0 deletions apps/sim/app/(landing)/blog/post-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function PostGrid({ posts }: { posts: Post[] }) {
src={p.ogImage}
alt={p.title}
sizes='(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw'
unoptimized
priority={index < 6}
loading={index < 6 ? undefined : 'lazy'}
fill
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import {
Button,
Input,
Expand Down Expand Up @@ -39,10 +39,55 @@ export function CreditBalance({
const [validationError, setValidationError] = useState<string | null>(null)
const [requestId, setRequestId] = useState<string | null>(null)
const purchaseCredits = usePurchaseCredits()
const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)

const dollarAmount = Number.parseInt(amount, 10) || 0
const creditPreview = dollarsToCredits(dollarAmount)

const clearCloseTimeout = () => {
if (closeTimeoutRef.current) {
clearTimeout(closeTimeoutRef.current)
closeTimeoutRef.current = null
}
}

const resetModalState = () => {
setAmount('')
setValidationError(null)
purchaseCredits.reset()
}

const openModal = () => {
clearCloseTimeout()
resetModalState()
setRequestId(crypto.randomUUID())
setIsOpen(true)
}

const closeModal = () => {
clearCloseTimeout()
setIsOpen(false)
setRequestId(null)
resetModalState()
}

useEffect(() => {
return () => {
clearCloseTimeout()
}
}, [])

const handleOpenChange = (open: boolean) => {
if (open) {
openModal()
return
}

if (!purchaseCredits.isPending) {
closeModal()
}
}

const handleAmountChange = (value: string) => {
const numericValue = value.replace(/[^0-9]/g, '')
setAmount(numericValue)
Expand All @@ -68,27 +113,16 @@ export function CreditBalance({
{ amount: numAmount, requestId },
{
onSuccess: () => {
setTimeout(() => {
setIsOpen(false)
onPurchaseComplete?.()
onPurchaseComplete?.()
clearCloseTimeout()
closeTimeoutRef.current = setTimeout(() => {
closeModal()
}, 1500)
},
}
)
}

const handleOpenChange = (open: boolean) => {
setIsOpen(open)
if (open) {
setRequestId(crypto.randomUUID())
} else {
setAmount('')
setValidationError(null)
purchaseCredits.reset()
setRequestId(null)
}
}

const displayError = validationError || purchaseCredits.error?.message

return (
Expand All @@ -103,9 +137,7 @@ export function CreditBalance({
{canPurchase && (
<Modal open={isOpen} onOpenChange={handleOpenChange}>
<ModalTrigger asChild>
<Button variant='active' className='h-[32px] text-[13px]'>
Add Credits
</Button>
<Button variant='active'>Add Credits</Button>
</ModalTrigger>
<ModalContent size='sm'>
<ModalHeader>Add Credits</ModalHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ function CreditPlanCard({

return (
<article className='flex flex-1 flex-col overflow-hidden rounded-[6px] border border-[var(--border-1)] bg-[var(--surface-5)]'>
<div className='flex items-center justify-between gap-[8px] px-[14px] py-[10px]'>
<div className='flex min-h-[44px] items-center justify-between gap-[8px] px-[14px] py-[10px]'>
<span className='font-medium text-[14px] text-[var(--text-primary)]'>{name}</span>
<div className='flex items-baseline gap-[4px]'>
<div className='flex shrink-0 items-baseline gap-[4px] whitespace-nowrap'>
<span className='font-medium text-[14px] text-[var(--text-primary)]'>
${isAnnual ? discountedMonthly : dollars}
</span>
Expand All @@ -207,7 +207,7 @@ function CreditPlanCard({
</div>
</div>

<div className='flex items-center gap-[12px] border-[var(--border-1)] border-t bg-[var(--surface-4)] px-[14px] py-[10px]'>
<div className='flex items-center gap-[12px] rounded-t-[8px] border-[var(--border-1)] border-t bg-[var(--surface-4)] px-[14px] py-[10px]'>
<div className='flex flex-col'>
<span className='font-semibold text-[18px] text-[var(--text-primary)]'>
{credits.toLocaleString()}
Expand Down Expand Up @@ -242,13 +242,13 @@ function CreditPlanCard({
</div>
)}

<div className='border-[var(--border-1)] border-t bg-[var(--surface-4)] px-[14px] py-[14px]'>
<div className='flex min-h-[60px] items-center border-[var(--border-1)] border-t bg-[var(--surface-4)] px-[14px] py-[14px]'>
{isCurrentPlan ? (
<Button onClick={onManagePlan} className='w-full' variant='default'>
<Button onClick={onManagePlan} className='h-[32px] w-full' variant='default'>
{isCancelledAtPeriodEnd ? 'Restore Subscription' : 'Manage plan'}
</Button>
) : (
<Button onClick={onButtonClick} className='w-full' variant='primary'>
<Button onClick={onButtonClick} className='h-[32px] w-full' variant='primary'>
{buttonText}
</Button>
)}
Expand Down Expand Up @@ -933,9 +933,9 @@ export function Subscription() {

{/* Billing details section */}
{(subscription.isPaid || (!isLoading && isTeamAdmin)) && (
<div className='flex flex-col'>
<div className='flex flex-col gap-[16px]'>
{subscription.isPaid && permissions.canViewUsageInfo && (
<div className='py-[2px]'>
<div>
<CreditBalance
balance={subscriptionData?.data?.creditBalance ?? 0}
canPurchase={hasUsablePaidAccess && permissions.canEditUsageLimit}
Expand All @@ -952,7 +952,7 @@ export function Subscription() {
subscriptionData?.data?.periodEnd &&
!permissions.showTeamMemberView &&
!permissions.isEnterpriseMember && (
<div className='flex items-center justify-between border-[var(--border-1)] border-t pt-[16px]'>
<div className='flex items-center justify-between gap-[16px]'>
<Label>{isCancelledAtPeriodEnd ? 'Access Until' : 'Next Billing Date'}</Label>
<span className='text-[13px] text-[var(--text-secondary)]'>
{new Date(subscriptionData.data.periodEnd).toLocaleDateString()}
Expand All @@ -961,19 +961,18 @@ export function Subscription() {
)}

{subscription.isPaid && permissions.canViewUsageInfo && (
<div className='border-[var(--border-1)] border-t pt-[16px]'>
<div>
<BillingUsageNotificationsToggle />
</div>
)}

{subscription.isPaid &&
!permissions.showTeamMemberView &&
!permissions.isEnterpriseMember && (
<div className='flex items-center justify-between border-[var(--border-1)] border-t pt-[16px]'>
<div className='flex items-center justify-between gap-[16px]'>
<Label>Invoices</Label>
<Button
variant='active'
size='sm'
disabled={openBillingPortal.isPending}
onClick={() => {
const portalWindow = window.open('', '_blank')
Expand Down Expand Up @@ -1008,7 +1007,7 @@ export function Subscription() {
)}

{!isLoading && isTeamAdmin && (
<div className='flex items-center justify-between border-[var(--border-1)] border-t pt-[16px]'>
<div className='flex items-center justify-between gap-[16px]'>
<div className='flex items-center gap-[6px]'>
<Label htmlFor='billed-account'>Billed Account</Label>
<Tooltip.Root>
Expand Down
Loading