Skip to content
Open
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
4 changes: 2 additions & 2 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8474,8 +8474,8 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
pricing: 'Preise',
},
requestEarlyCancellation: {
title: 'Frühzeitige Kündigung anfordern',
subtitle: 'Was ist der Hauptgrund, warum du eine vorzeitige Kündigung beantragst?',
title: 'Abonnement kündigen',
subtitle: 'Was ist der Hauptgrund, warum du dein Abonnement kündigst?',
subscriptionCanceled: {
title: 'Abonnement gekündigt',
subtitle: 'Dein Jahresabonnement wurde gekündigt.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8449,8 +8449,8 @@ const translations = {
pricing: 'Pricing',
},
requestEarlyCancellation: {
title: 'Request early cancellation',
subtitle: 'What’s the main reason you’re requesting early cancellation?',
title: 'Cancel subscription',
subtitle: 'What’s the main reason you’re canceling your subscription?',
subscriptionCanceled: {
title: 'Subscription canceled',
subtitle: 'Your annual subscription has been canceled.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8725,8 +8725,8 @@ ${amount} para ${merchant} - ${date}`,
pricing: 'Precios',
},
requestEarlyCancellation: {
title: 'Solicitar cancelación anticipada',
subtitle: '¿Cuál es la razón principal por la que solicitas la cancelación anticipada?',
title: 'Cancelar suscripción',
subtitle: '¿Cuál es la razón principal por la que solicitas cancelar tu suscripción?',
subscriptionCanceled: {
title: 'Suscripción cancelada',
subtitle: 'Tu suscripción anual ha sido cancelada.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8496,8 +8496,8 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
pricing: 'Tarification',
},
requestEarlyCancellation: {
title: 'Demander une résiliation anticipée',
subtitle: 'Quelle est la principale raison pour laquelle vous demandez une résiliation anticipée ?',
title: "Annuler l'abonnement",
subtitle: 'Quelle est la principale raison pour laquelle vous souhaitez résilier votre abonnement ?',
subscriptionCanceled: {
title: 'Abonnement annulé',
subtitle: 'Votre abonnement annuel a été annulé.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8462,8 +8462,8 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
pricing: 'Prezzi',
},
requestEarlyCancellation: {
title: 'Richiedi annullamento anticipato',
subtitle: 'Qual è il motivo principale per cui stai richiedendo l’annullamento anticipato?',
title: 'Annulla abbonamento',
subtitle: 'Qual è il motivo principale per cui vuoi annullare il tuo abbonamento?',
subscriptionCanceled: {
title: 'Abbonamento annullato',
subtitle: 'Il tuo abbonamento annuale è stato annullato.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8356,8 +8356,8 @@ ${reportName}
pricing: '料金',
},
requestEarlyCancellation: {
title: '早期解約をリクエスト',
subtitle: '早期解約を申請する主な理由を教えてください。',
title: 'サブスクリプションをキャンセル',
subtitle: 'サブスクリプションをキャンセルする主な理由を教えてください。',
subscriptionCanceled: {
title: 'サブスクリプションを解約しました',
subtitle: '年間サブスクリプションは解約されました。',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8440,8 +8440,8 @@ Voeg meer bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
pricing: 'Prijzen',
},
requestEarlyCancellation: {
title: 'Vroegtijdige annulering aanvragen',
subtitle: 'Wat is de belangrijkste reden dat je om vervroegde annulering vraagt?',
title: 'Abonnement opzeggen',
subtitle: 'Wat is de belangrijkste reden dat je je abonnement opzegt?',
subscriptionCanceled: {
title: 'Abonnement geannuleerd',
subtitle: 'Je jaarlijkse abonnement is opgezegd.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8421,8 +8421,8 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
pricing: 'Cennik',
},
requestEarlyCancellation: {
title: 'Poproś o wcześniejsze anulowanie',
subtitle: 'Jaki jest główny powód, dla którego prosisz o wcześniejsze anulowanie?',
title: 'Anuluj subskrypcję',
subtitle: 'Jaki jest główny powód, dla którego prosisz o anulowanie subskrypcji?',
subscriptionCanceled: {
title: 'Subskrypcja anulowana',
subtitle: 'Twoja subskrypcja roczna została anulowana.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8430,8 +8430,8 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
pricing: 'Preços',
},
requestEarlyCancellation: {
title: 'Solicitar cancelamento antecipado',
subtitle: 'Qual é o principal motivo pelo qual você está solicitando o cancelamento antecipado?',
title: 'Cancelar assinatura',
subtitle: 'Qual é o principal motivo pelo qual você está deseja cancelar sua assinatura?',
subscriptionCanceled: {
title: 'Assinatura cancelada',
subtitle: 'Sua assinatura anual foi cancelada.',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8193,8 +8193,8 @@ ${reportName}
pricing: '定价',
},
requestEarlyCancellation: {
title: '请求提前取消',
subtitle: '您申请提前取消的主要原因是什么?',
title: '取消订阅',
subtitle: '您取消订阅的主要原因是什么?',
subscriptionCanceled: {
title: '订阅已取消',
subtitle: '您的年度订阅已被取消。',
Expand Down
35 changes: 35 additions & 0 deletions src/libs/SubscriptionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
};

let currentUserAccountID = -1;
Onyx.connect({

Check warning on line 56 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (value) => {
currentUserAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID;
Expand All @@ -61,13 +61,13 @@
});

let privateAmountOwed: OnyxEntry<number>;
Onyx.connect({

Check warning on line 64 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED,
callback: (value) => (privateAmountOwed = value),
});

let deprecatedAllPolicies: OnyxCollection<Policy>;
Onyx.connect({

Check warning on line 70 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (value) => (deprecatedAllPolicies = value),
waitForCollectionCallback: true,
Expand Down Expand Up @@ -452,6 +452,40 @@
return userBillingFundID !== undefined;
}

/**
* Whether the user is eligible to cancel their subscription.
* Annual subscribers who have committed to a subscription can cancel.
* Excludes: non-annual users, active trial users, pre-trial users, and expired trial users who never subscribed.
*/
function canCancelSubscription(
subscriptionType: SubscriptionType | undefined,
firstDayFreeTrial: string | undefined,
lastDayFreeTrial: string | undefined,
userBillingFundID: number | undefined,
hasPurchases: boolean | undefined,
): boolean {
if (subscriptionType !== CONST.SUBSCRIPTION.TYPE.ANNUAL) {
return false;
}

// User is currently on a free trial
if (isUserOnFreeTrial(firstDayFreeTrial, lastDayFreeTrial)) {
return false;
}

// User is in pre-trial state (trial dates exist but trial hasn't started yet)
if (firstDayFreeTrial && !hasUserFreeTrialEnded(lastDayFreeTrial)) {
return false;
}

// User's trial ended — only allow cancellation if they have a card or have been billed before
if (hasUserFreeTrialEnded(lastDayFreeTrial) && !doesUserHavePaymentCardAdded(userBillingFundID) && !hasPurchases) {
return false;
}

return true;
}

/**
* Whether the user's billable actions should be restricted.
*/
Expand Down Expand Up @@ -609,6 +643,7 @@

export {
calculateRemainingFreeTrialDays,
canCancelSubscription,
doesUserHavePaymentCardAdded,
getCardForSubscriptionBilling,
getFreeTrialText,
Expand Down
26 changes: 25 additions & 1 deletion src/libs/actions/Subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,31 @@ function cancelBillingSubscription(cancellationReason: FeedbackSurveyOptionID, c
cancellationNote,
};

API.write(WRITE_COMMANDS.CANCEL_BILLING_SUBSCRIPTION, parameters);
const onyxData: OnyxData<typeof ONYXKEYS.FORMS.REQUEST_EARLY_CANCELLATION_FORM> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REQUEST_EARLY_CANCELLATION_FORM,
value: {isLoading: true},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REQUEST_EARLY_CANCELLATION_FORM,
value: {isLoading: false},
},
],
failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REQUEST_EARLY_CANCELLATION_FORM,
value: {isLoading: false},
},
],
};

API.write(WRITE_COMMANDS.CANCEL_BILLING_SUBSCRIPTION, parameters, onyxData);
}

function requestTaxExempt() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function CancelSubscriptionMenuItem() {
return null;
}

export default CancelSubscriptionMenuItem;
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import Navigation from '@libs/Navigation/Navigation';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

function RequestEarlyCancellationMenuItem() {
const icons = useMemoizedLazyExpensifyIcons(['CalendarSolid']);
function CancelSubscriptionMenuItem() {
const icons = useMemoizedLazyExpensifyIcons(['CircleSlash']);
const {translate} = useLocalize();
const styles = useThemeStyles();
const {isActingAsDelegate} = useDelegateNoAccessState();
const {showDelegateNoAccessModal} = useDelegateNoAccessActions();

const handleRequestEarlyCancellationPress = () => {
const handleCancelSubscriptionPress = () => {
if (isActingAsDelegate) {
showDelegateNoAccessModal();
return;
Expand All @@ -25,13 +25,14 @@ function RequestEarlyCancellationMenuItem() {
return (
<MenuItem
title={translate('subscription.requestEarlyCancellation.title')}
icon={icons.CalendarSolid}
icon={icons.CircleSlash}
shouldShowRightIcon
wrapperStyle={styles.sectionMenuItemTopDescription}
onPress={handleRequestEarlyCancellationPress}
titleStyle={styles.textStrong}
onPress={handleCancelSubscriptionPress}
sentryLabel={CONST.SENTRY_LABEL.SETTINGS_SUBSCRIPTION.REQUEST_EARLY_CANCELLATION}
/>
);
}

export default RequestEarlyCancellationMenuItem;
export default CancelSubscriptionMenuItem;
15 changes: 12 additions & 3 deletions src/pages/settings/Subscription/CardSection/CardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ import DateUtils from '@libs/DateUtils';
import Navigation from '@libs/Navigation/Navigation';
import {getPaymentMethodDescription} from '@libs/PaymentUtils';
import {buildQueryStringFromFilterFormValues} from '@libs/SearchQueryUtils';
import {hasCardAuthenticatedError, isUserOnFreeTrial, shouldShowDiscountBanner, shouldShowPreTrialBillingBanner, shouldShowTrialEndedUI} from '@libs/SubscriptionUtils';
import {
canCancelSubscription,
hasCardAuthenticatedError,
isUserOnFreeTrial,
shouldShowDiscountBanner,
shouldShowPreTrialBillingBanner,
shouldShowTrialEndedUI,
} from '@libs/SubscriptionUtils';
import {verifySetupIntent} from '@userActions/PaymentMethods';
import {clearOutstandingBalance} from '@userActions/Subscription';
import CONST from '@src/CONST';
Expand All @@ -33,11 +40,11 @@ import PreTrialBillingBanner from './BillingBanner/PreTrialBillingBanner';
import SubscriptionBillingBanner from './BillingBanner/SubscriptionBillingBanner';
import TrialEndedBillingBanner from './BillingBanner/TrialEndedBillingBanner';
import TrialStartedBillingBanner from './BillingBanner/TrialStartedBillingBanner';
import CancelSubscriptionMenuItem from './CancelSubscriptionMenuItem';
import CardSectionActions from './CardSectionActions';
import CardSectionButton from './CardSectionButton';
import CardSectionDataEmpty from './CardSectionDataEmpty';
import getSectionSubtitle from './CardSectionSubtitle';
import RequestEarlyCancellationMenuItem from './RequestEarlyCancellationMenuItem';
import type {BillingStatusResult} from './utils';
import CardSectionUtils from './utils';

Expand Down Expand Up @@ -300,7 +307,9 @@ function CardSection() {
/>
)}

{!!(privateSubscription?.type === CONST.SUBSCRIPTION.TYPE.ANNUAL && account?.hasPurchases) && <RequestEarlyCancellationMenuItem />}
{!privateSubscription?.pendingFields?.type && canCancelSubscription(privateSubscription?.type, firstDayFreeTrial, lastDayFreeTrial, userBillingFundID, account?.hasPurchases) && (
<CancelSubscriptionMenuItem />
)}
</Section>
);
}
Expand Down

This file was deleted.

Loading
Loading