mirror of
https://github.com/langgenius/dify.git
synced 2026-11-10 21:35:45 +08:00
fix(billing): keep education checkout actions accessible on mobile
This commit is contained in:
3 files changed
+68
-13
No files matched your search
@@ -10,6 +10,7 @@ import {
|
||||
seedFeatures,
|
||||
} from '@/test/console/query-data'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createDeferred } from '@/test/deferred'
|
||||
import { PricingContent } from '../content'
|
||||
|
||||
let billingPopup: {
|
||||
@@ -219,11 +220,8 @@ it('offers education pricing before Team checkout when the discount has not been
|
||||
const { queryClient, show } = setup()
|
||||
seedFeatures(queryClient, { education: { enabled: true, activated: false } })
|
||||
seedEducationStatus(queryClient, { is_student: true })
|
||||
const checkout = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
||||
new Response(JSON.stringify({ url: 'https://billing.example.com/team-checkout' }), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
)
|
||||
const pending = createDeferred<Response>()
|
||||
const checkout = vi.spyOn(globalThis, 'fetch').mockReturnValue(pending.promise)
|
||||
show()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'billing.plansCommon.upgradeToTeam' }))
|
||||
@@ -234,6 +232,19 @@ it('offers education pricing before Team checkout when the discount has not been
|
||||
expect(checkout).not.toHaveBeenCalled()
|
||||
const navigate = vi.spyOn(window.location, 'href', 'set').mockImplementation(() => {})
|
||||
await user.click(screen.getByRole('button', { name: 'education.educationPricingConfirm.cancel' }))
|
||||
const switchPlan = screen.getByRole('button', {
|
||||
name: 'education.educationPricingConfirm.continue',
|
||||
})
|
||||
expect(switchPlan).toBeDisabled()
|
||||
await user.click(switchPlan)
|
||||
expect(checkout).toHaveBeenCalledTimes(1)
|
||||
await act(async () =>
|
||||
pending.resolve(
|
||||
new Response(JSON.stringify({ url: 'https://billing.example.com/team-checkout' }), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
),
|
||||
)
|
||||
await waitFor(() =>
|
||||
expect(navigate).toHaveBeenCalledWith('https://billing.example.com/team-checkout'),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { page } from 'vite-plus/test/browser'
|
||||
import { render } from 'vitest-browser-react'
|
||||
import { createConsoleQueryWrapper } from '@/test/console/query-data'
|
||||
import { CloudPlanItem } from '../plans/cloud-plan-item'
|
||||
|
||||
vi.mock('@/context/workspace-state', async () => {
|
||||
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createWorkspaceStateModuleMock(() => ({ isCurrentWorkspaceManager: true }))
|
||||
})
|
||||
|
||||
it('keeps both education checkout actions inside the dialog on a narrow phone', async () => {
|
||||
await page.viewport(320, 700)
|
||||
const { wrapper: Provider } = createConsoleQueryWrapper()
|
||||
await render(
|
||||
<Provider>
|
||||
<CloudPlanItem
|
||||
plan="team"
|
||||
billingInterval="month"
|
||||
billing={{
|
||||
currentPlan: 'sandbox',
|
||||
currentBillingInterval: 'month',
|
||||
isEducationDiscountActivated: false,
|
||||
isEducationDiscountEligible: true,
|
||||
}}
|
||||
/>
|
||||
</Provider>,
|
||||
)
|
||||
await page.getByRole('button', { name: 'billing.plansCommon.upgradeToTeam' }).click()
|
||||
const dialog = page.getByRole('dialog')
|
||||
await expect.element(dialog).toBeVisible()
|
||||
const bounds = dialog.element().getBoundingClientRect()
|
||||
for (const name of [
|
||||
'education.educationPricingConfirm.cancel',
|
||||
'education.educationPricingConfirm.continue',
|
||||
]) {
|
||||
const action = dialog.getByRole('button', { name })
|
||||
await expect.element(action).toBeVisible()
|
||||
const rect = action.element().getBoundingClientRect()
|
||||
expect(rect.left).toBeGreaterThanOrEqual(bounds.left)
|
||||
expect(rect.right).toBeLessThanOrEqual(bounds.right)
|
||||
}
|
||||
})
|
||||
@@ -157,9 +157,6 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
|
||||
await runPlanAction()
|
||||
}
|
||||
const handleUseEducationDiscount = async () => {
|
||||
await handleEducationDiscount()
|
||||
}
|
||||
const handleContinueWithoutEducationDiscount = async () => {
|
||||
await runPlanAction()
|
||||
setShowEducationPricingConfirm(false)
|
||||
@@ -223,6 +220,10 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
variant="tertiary"
|
||||
size={null}
|
||||
disabled={isPlanDisabled}
|
||||
loading={
|
||||
!showEducationPricingConfirm &&
|
||||
(isPlanActionPending || isEducationDiscountLoading)
|
||||
}
|
||||
className={cn(
|
||||
'h-auto min-h-15 w-full rounded-lg border p-3 text-2xl leading-[30px] font-medium whitespace-normal shadow-none disabled:cursor-default',
|
||||
isPrimaryAction
|
||||
@@ -236,7 +237,7 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
<span className="min-w-0">{buttonLabel}</span>
|
||||
</Button>
|
||||
{educationDiscountWarningText && (
|
||||
<div className="absolute inset-x-0 top-full mt-1.5 text-start system-2xs-medium text-text-tertiary">
|
||||
<div className="mt-1.5 text-start system-2xs-medium text-text-tertiary">
|
||||
{educationDiscountWarningText}
|
||||
</div>
|
||||
)}
|
||||
@@ -258,22 +259,23 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
aria-label={t(($) => $['operation.close'], { ns: 'common' })}
|
||||
/>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogFooter className="max-sm:flex-col max-sm:items-stretch">
|
||||
<Button
|
||||
size="large"
|
||||
onClick={handleContinueWithoutEducationDiscount}
|
||||
disabled={isEducationDiscountLoading}
|
||||
loading={isPlanActionPending}
|
||||
className="min-w-38"
|
||||
className="h-auto min-h-9 w-full whitespace-normal sm:w-auto sm:min-w-38"
|
||||
>
|
||||
{t(($) => $['educationPricingConfirm.cancel'], { ns: 'education' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="large"
|
||||
onClick={handleUseEducationDiscount}
|
||||
onClick={handleEducationDiscount}
|
||||
disabled={isPlanActionPending}
|
||||
loading={isEducationDiscountLoading}
|
||||
className="min-w-61"
|
||||
className="h-auto min-h-9 w-full whitespace-normal sm:w-auto sm:min-w-61"
|
||||
>
|
||||
{t(($) => $['educationPricingConfirm.continue'], { ns: 'education' })}
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user