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
19 changes: 18 additions & 1 deletion sdks/js/packages/core/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
extensionsToTreatAsEsm: ['.ts', '.tsx'],
moduleNameMapper: {
'^~/(.*)$': '<rootDir>/$1',
'^(\\.{1,2}/.*)\\.js$': '$1'
},
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
tsconfig: {
module: 'ES2020',
moduleResolution: 'node'
}
}
]
}
};
4 changes: 2 additions & 2 deletions sdks/js/packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"release:ci": "release-it --ci --no-increment --npm.ignoreVersion",
"release:dry": "release-it --dry-run --npm.ignoreVersion",
"release": "release-it",
"test": "jest",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"gen:client": "npx swagger-typescript-api -p ../../../../proto/apidocs.swagger.yaml -o api-client --modular",
"build:client": "node scripts/gen-swagger-client.mjs"
},
Expand Down Expand Up @@ -99,7 +99,7 @@
"@connectrpc/connect-query": "^2.1.1",
"@connectrpc/connect-web": "^2.0.2",
"@hookform/resolvers": "^3.10.0",
"@raystack/proton": "0.1.0-2dbafa5913a214851fdc4f1beefbe27c4a6de55a",
"@raystack/proton": "0.1.0-fba39927b8b974dc1cc1ae0f05f1390580ec6d58",
"@tanstack/react-query": "^5.83.0",
"@tanstack/react-router": "1.58.17",
"axios": "^1.9.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@
DEFAULT_DATE_FORMAT,
SUBSCRIPTION_STATES
} from '~/react/utils/constants';
import { V1Beta1Plan, V1Beta1Subscription } from '~/src';
import { Subscription, Plan } from '@raystack/proton/frontier';

Check warning on line 6 in sdks/js/packages/core/react/components/common/upcoming-plan-change-banner/index.tsx

View workflow job for this annotation

GitHub Actions / JS SDK Lint

'Plan' is defined but never used
import styles from './styles.module.css';
import { InfoCircledIcon } from '@radix-ui/react-icons';
import dayjs from 'dayjs';
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useFrontier } from '~/react/contexts/FrontierContext';
import {
checkSimilarPlans,
getPlanChangeAction,
getPlanIntervalName,
getPlanNameWithInterval
} from '~/react/utils';
import { timestampToDayjs } from '~/utils/timestamp';

interface ChangeBannerProps {
isLoading?: boolean;
subscription?: V1Beta1Subscription;
subscription?: Subscription;
isAllowed: boolean;
}

Expand All @@ -34,47 +35,28 @@
activeOrganization,
billingAccount,
fetchActiveSubsciption,
basePlan
basePlan,
allPlans,
isAllPlansLoading
} = useFrontier();
const [upcomingPlan, setUpcomingPlan] = useState<V1Beta1Plan>();
const [isPlanLoading, setIsPlanLoading] = useState(false);
const [isPlanChangeLoading, setIsPlanChangeLoading] = useState(false);

const phases =
subscription?.phases?.filter(phase =>
dayjs(phase.effective_at).isAfter(dayjs())
timestampToDayjs(phase.effectiveAt)?.isAfter(dayjs())
) || [];

const nextPhase = phases?.[0];

const fetchPlan = useCallback(
async (planId: string) => {
setIsPlanLoading(true);
try {
const resp = await client?.frontierServiceGetPlan(planId);
const plan = resp?.data?.plan ?? {};
if (plan) {
setUpcomingPlan(plan);
} else {
setUpcomingPlan(undefined);
}
} catch (err) {
console.error(err);
} finally {
setIsPlanLoading(false);
}
},
[client]
);

useEffect(() => {
if (nextPhase?.plan_id) {
fetchPlan(nextPhase?.plan_id);
const upcomingPlan = useMemo(() => {
if (nextPhase?.planId && allPlans.length > 0) {
const plan = allPlans.find(p => p.id === nextPhase?.planId);
return plan;
}
}, [fetchPlan, nextPhase?.plan_id]);
}, [nextPhase?.planId, allPlans]);

const expiryDate = nextPhase?.effective_at
? dayjs(nextPhase?.effective_at).format(
const expiryDate = nextPhase?.effectiveAt
? timestampToDayjs(nextPhase?.effectiveAt)?.format(
config?.dateFormat || DEFAULT_DATE_FORMAT
)
: '';
Expand All @@ -87,7 +69,7 @@
Number(activePlanMetadata?.weightage)
);

const showLoader = isLoading || isPlanLoading;
const showLoader = isLoading || isAllPlansLoading;

const onPlanChangeCancel = useCallback(async () => {
setIsPlanChangeLoading(true);
Expand Down Expand Up @@ -125,17 +107,14 @@
const currentPlanName = getPlanNameWithInterval(activePlan);
const upcomingPlanName = getPlanNameWithInterval(upcomingPlan || basePlan);

const areSimilarPlans = checkSimilarPlans(
activePlan || {},
upcomingPlan || {}
);
const areSimilarPlans = checkSimilarPlans(activePlan, upcomingPlan);

const resumePlanTitle = areSimilarPlans
? getPlanIntervalName(activePlan)
: activePlan?.title;

const showBanner =
nextPhase?.plan_id ||
nextPhase?.planId ||
(subscription?.state === SUBSCRIPTION_STATES.ACTIVE &&
nextPhase?.reason === 'cancel');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';

Check warning on line 1 in sdks/js/packages/core/react/components/organization/billing/cycle-switch/index.tsx

View workflow job for this annotation

GitHub Actions / JS SDK Lint

'useEffect' is defined but never used
import {
Button,
Skeleton,
Expand All @@ -10,24 +10,29 @@
} from '@raystack/apsara';
import { useNavigate, useParams } from '@tanstack/react-router';
import { useFrontier } from '~/react/contexts/FrontierContext';
import { V1Beta1Plan } from '~/src';
import { getPlanIntervalName, getPlanPrice } from '~/react/utils';
import * as _ from 'lodash';
import { usePlans } from '../../plans/hooks/usePlans';
import dayjs from 'dayjs';
import { DEFAULT_DATE_FORMAT } from '~/react/utils/constants';
import cross from '~/react/assets/cross.svg';
import styles from '../../organization.module.css';
import { timestampToDayjs } from '~/utils/timestamp';
import { Plan } from '@raystack/proton/frontier';

export function ConfirmCycleSwitch() {
const { activePlan, client, paymentMethod, config, activeSubscription } =
useFrontier();
const {
activePlan,
paymentMethod,
config,
activeSubscription,
allPlans,
isAllPlansLoading
} = useFrontier();
const navigate = useNavigate({ from: '/billing/cycle-switch/$planId' });
const { planId } = useParams({ from: '/billing/cycle-switch/$planId' });
const dateFormat = config?.dateFormat || DEFAULT_DATE_FORMAT;

const [isPlanLoading, setIsPlanLoading] = useState(false);
const [nextPlan, setNextPlan] = useState<V1Beta1Plan>();
const [isCycleSwitching, setCycleSwitching] = useState(false);

const closeModal = useCallback(
Expand All @@ -42,6 +47,13 @@
verifyPlanChange
} = usePlans();

const nextPlan = useMemo(() => {
if (planId && allPlans.length > 0) {
const plan = allPlans.find(p => p.id === planId);
return plan;
}
}, [planId, allPlans]);

const nextPlanPrice = nextPlan ? getPlanPrice(nextPlan) : { amount: 0 };
const isPaymentMethodRequired =
_.isEmpty(paymentMethod) && nextPlanPrice.amount > 0;
Expand All @@ -56,28 +68,7 @@
(Number(activePlanMetadata?.weightage) || 0) >
0;

useEffect(() => {
async function getNextPlan(nextPlanId: string) {
setIsPlanLoading(true);
try {
const resp = await client?.frontierServiceGetPlan(nextPlanId);
const plan = resp?.data?.plan;
setNextPlan(plan);
} catch (err: any) {
toast.error('Something went wrong', {
description: err.message
});
console.error(err);
} finally {
setIsPlanLoading(false);
}
}
if (planId) {
getNextPlan(planId);
}
}, [client, planId]);

const isLoading = isPlanLoading;
const isLoading = isAllPlansLoading;

async function onConfirm() {
setCycleSwitching(true);
Expand All @@ -101,9 +92,9 @@
});
if (planPhase) {
closeModal();
const changeDate = dayjs(planPhase?.effective_at).format(
dateFormat
);
const changeDate = timestampToDayjs(
planPhase?.effectiveAt
)?.format(dateFormat);
toast.success(`Plan cycle switch successful`, {
description: `Your plan cycle will switched to ${nextPlanIntervalName} on ${changeDate}`
});
Expand All @@ -122,8 +113,8 @@
}
}

const cycleSwitchDate = activeSubscription?.current_period_end_at
? dayjs(activeSubscription?.current_period_end_at).format(
const cycleSwitchDate = activeSubscription?.currentPeriodEndAt
? timestampToDayjs(activeSubscription?.currentPeriodEndAt)?.format(
config?.dateFormat || DEFAULT_DATE_FORMAT
)
: 'the next billing cycle';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { useFrontier } from '~/react/contexts/FrontierContext';
import { useCallback, useEffect, useState } from 'react';
import billingStyles from './billing.module.css';
import {
V1Beta1BillingAccount,
V1Beta1CheckoutSetupBody,
V1Beta1Invoice
} from '~/src';
import { BillingAccount } from '@raystack/proton/frontier';
// import { converBillingAddressToString } from '~/react/utils';
import Invoices from './invoices';
import qs from 'query-string';
Expand Down Expand Up @@ -70,7 +70,7 @@ const BillingHeader = ({
};

interface BillingDetailsProps {
billingAccount?: V1Beta1BillingAccount;
billingAccount?: BillingAccount;
onAddDetailsClick?: () => void;
isLoading: boolean;
isAllowed: boolean;
Expand Down Expand Up @@ -165,13 +165,13 @@ export default function Billing() {
);

useEffect(() => {
if (billingAccount?.id && billingAccount?.org_id) {
fetchInvoices(billingAccount?.org_id, billingAccount?.id);
if (billingAccount?.id && billingAccount?.orgId) {
fetchInvoices(billingAccount?.orgId, billingAccount?.id);
}
}, [billingAccount?.id, billingAccount?.org_id, client, fetchInvoices]);
}, [billingAccount?.id, billingAccount?.orgId, client, fetchInvoices]);

const onAddDetailsClick = useCallback(async () => {
const orgId = billingAccount?.org_id || '';
const orgId = billingAccount?.orgId || '';
const billingAccountId = billingAccount?.id || '';
if (billingAccountId && orgId) {
try {
Expand All @@ -180,7 +180,7 @@ export default function Billing() {
details: btoa(
qs.stringify({
billing_id: billingAccount?.id,
organization_id: billingAccount?.org_id,
organization_id: billingAccount?.orgId,
type: 'billing'
})
),
Expand All @@ -196,7 +196,7 @@ export default function Billing() {
};

const resp = await client?.frontierServiceCreateCheckout(
billingAccount?.org_id || '',
billingAccount?.orgId || '',
billingAccount?.id || '',
{
cancel_url,
Expand All @@ -215,7 +215,7 @@ export default function Billing() {
}
}, [
billingAccount?.id,
billingAccount?.org_id,
billingAccount?.orgId,
client,
config?.billing?.cancelUrl,
config?.billing?.successUrl
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Button, Skeleton, Image, Text, Flex } from '@raystack/apsara';
import { INVOICE_STATES, SUBSCRIPTION_STATES } from '~/react/utils/constants';
import { V1Beta1Invoice, V1Beta1Subscription } from '~/src';
import { V1Beta1Invoice } from '~/src';
import { Subscription } from '@raystack/proton/frontier';
import billingStyles from './billing.module.css';
import exclamationTriangle from '~/react/assets/exclamation-triangle.svg';
import dayjs from 'dayjs';
import { useCallback } from 'react';

interface PaymentIssueProps {
isLoading?: boolean;
subscription?: V1Beta1Subscription;
subscription?: Subscription;
invoices: V1Beta1Invoice[];
}

Expand Down
Loading
Loading