<commit_before>import { ReactNode } from 'react';
import { c } from 'ttag';
import { getCalendars } from '@proton/shared/lib/models/calendarsModel';
import { deleteSubscription } from '@proton/shared/lib/api/payments';
import { hasBonuses } from '@proton/shared/lib/helpers/organization';
import { MAX_CALENDARS_PER_FREE_USER } from '@proton/shared/lib/calendar/constants';
import { Calendar, CalendarUrlsResponse } from '@proton/shared/lib/interfaces/calendar';
import { getPublicLinks } from '@proton/shared/lib/api/calendars';
import { getIsPersonalCalendar } from '@proton/shared/lib/calendar/subscribe/helpers';
import unary from '@proton/utils/unary';
import { hasMigrationDiscount, hasNewVisionary } from '@proton/shared/lib/helpers/subscription';
import { PLANS, PLAN_SERVICES } from '@proton/shared/lib/constants';
import { toMap } from '@proton/shared/lib/helpers/object';
import { hasBit } from '@proton/shared/lib/helpers/bitset';
import Button, { ButtonProps } from '../../../components/button/Button';
import {
    useApi,
    useUser,
    useNotifications,
    useLoading,
    useModals,
    useEventManager,
    useOrganization,
    usePlans,
    useSubscription,
    useVPNCountriesCount,
    useVPNServersCount,
} from '../../../hooks';
import LossLoyaltyModal from '../LossLoyaltyModal';
import DowngradeModal from '../DowngradeModal';
import HighlightPlanDowngradeModal from './HighlightPlanDowngradeModal';
import CalendarDowngradeModal from './CalendarDowngradeModal';
import MemberDowngradeModal from '../MemberDowngradeModal';
import { DiscountWarningModal, NewVisionaryWarningModal } from './PlanLossWarningModal';
import FeedbackDowngradeModal, { FeedbackDowngradeData } from './FeedbackDowngradeModal';
import { getShortPlan } from '../features/plan';
import { formatPlans } from './helpers';

const { MAIL, VPN } = PLAN_SERVICES;

interface Props extends Omit<ButtonProps, 'loading' | 'onClick'> {
    children: ReactNode;
}

const UnsubscribeButton = ({ className, children, ...rest }: Props) => {
    const [user] = useUser();
    const [subscription, loadingSubscription] = useSubscription();
    const [organization] = useOrganization();
    const [plans, loadingPlans] = usePlans();
    const [vpnCountries] = useVPNCountriesCount();
    const [vpnServers] = useVPNServersCount();
    const { createNotification, hideNotification } = useNotifications();
    const { createModal } = useModals();
    const api = useApi();
    const { call } = useEventManager();
    const [loading, withLoading] = useLoading();

    const { Plans = [], PeriodEnd = 0 } = subscription || {};
    const { plan } = formatPlans(Plans);

    const currentPlan = plan;
    const plansMap = toMap(plans, 'Name');

    const handleUnsubscribe = async (data: FeedbackDowngradeData) => {
        const downgradeNotificationId = createNotification({
            type: 'info',
            text: c('State').t`Downgrading your account, please wait`,
            expiration: 99999,
        });

        try {
            await api(deleteSubscription(data));
            await call();
            createNotification({ text: c('Success').t`You have successfully unsubscribed` });
        } finally {
            hideNotification(downgradeNotificationId);
        }
    };

    const handleClick = async () => {
        if (user.isFree) {
            return createNotification({ type: 'error', text: c('Info').t`You already have a free account` });
        }

        // Start promise early
        const calendarPromise = (async () => {
            const calendars: Calendar[] = await getCalendars(api);
            const personalCalendars = calendars.filter(unary(getIsPersonalCalendar));

            const hasLinks = !!(
                await Promise.all(
                    personalCalendars.map((calendar) => api<CalendarUrlsResponse>(getPublicLinks(calendar.ID)))
                )
            ).flatMap(({ CalendarUrls }) => CalendarUrls).length;

            return personalCalendars.length > MAX_CALENDARS_PER_FREE_USER || hasLinks;
        })();

        if (hasMigrationDiscount(subscription)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<DiscountWarningModal type="downgrade" onClose={reject} onConfirm={resolve} />);
            });
        }

        if (hasNewVisionary(subscription)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<NewVisionaryWarningModal type="downgrade" onClose={reject} onConfirm={resolve} />);
            });
        }

        const shortPlan = currentPlan
            ? getShortPlan(currentPlan.Name as PLANS, plansMap, vpnCountries, vpnServers)
            : undefined;
        // We only show the plan downgrade plan modal for plans that are defined with features
        if (shortPlan) {
            await new Promise<void>((resolve, reject) => {
                createModal(
                    <HighlightPlanDowngradeModal
                        shortPlan={shortPlan}
                        periodEnd={PeriodEnd}
                        onConfirm={resolve}
                        onClose={reject}
                    />
                );
            });
        }

        if (await calendarPromise) {
            await new Promise<void>((resolve, reject) => {
                createModal(<CalendarDowngradeModal onConfirm={reject} onClose={reject} />);
            });
        }

        if (hasBonuses(organization)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<LossLoyaltyModal organization={organization} onConfirm={resolve} onClose={reject} />);
            });
        }

        if (organization.UsedMembers > 1) {
            await new Promise<void>((resolve, reject) => {
                createModal(<MemberDowngradeModal organization={organization} onConfirm={resolve} onClose={reject} />);
            });
        }

        const hasMail = hasBit(user.Services, MAIL);
        const hasVpn = hasBit(user.Services, VPN);

        if (hasMail || hasVpn) {
            await new Promise<void>((resolve, reject) => {
                createModal(<DowngradeModal hasMail={hasMail} hasVpn={hasVpn} onConfirm={resolve} onClose={reject} />);
            });
        }

        const data = await new Promise<FeedbackDowngradeData>((resolve, reject) => {
            createModal(<FeedbackDowngradeModal user={user} onSubmit={resolve} onClose={reject} />);
        });

        return handleUnsubscribe(data);
    };

    return (
        <Button<commit_msg>Check paid services for downgrade modal<commit_after>import { ReactNode } from 'react';
import { c } from 'ttag';
import { getCalendars } from '@proton/shared/lib/models/calendarsModel';
import { deleteSubscription } from '@proton/shared/lib/api/payments';
import { hasBonuses } from '@proton/shared/lib/helpers/organization';
import { MAX_CALENDARS_PER_FREE_USER } from '@proton/shared/lib/calendar/constants';
import { Calendar, CalendarUrlsResponse } from '@proton/shared/lib/interfaces/calendar';
import { getPublicLinks } from '@proton/shared/lib/api/calendars';
import { getIsPersonalCalendar } from '@proton/shared/lib/calendar/subscribe/helpers';
import unary from '@proton/utils/unary';
import { hasMigrationDiscount, hasNewVisionary } from '@proton/shared/lib/helpers/subscription';
import { PLANS, PLAN_SERVICES } from '@proton/shared/lib/constants';
import { toMap } from '@proton/shared/lib/helpers/object';
import { hasBit } from '@proton/shared/lib/helpers/bitset';
import Button, { ButtonProps } from '../../../components/button/Button';
import {
    useApi,
    useUser,
    useNotifications,
    useLoading,
    useModals,
    useEventManager,
    useOrganization,
    usePlans,
    useSubscription,
    useVPNCountriesCount,
    useVPNServersCount,
} from '../../../hooks';
import LossLoyaltyModal from '../LossLoyaltyModal';
import DowngradeModal from '../DowngradeModal';
import HighlightPlanDowngradeModal from './HighlightPlanDowngradeModal';
import CalendarDowngradeModal from './CalendarDowngradeModal';
import MemberDowngradeModal from '../MemberDowngradeModal';
import { DiscountWarningModal, NewVisionaryWarningModal } from './PlanLossWarningModal';
import FeedbackDowngradeModal, { FeedbackDowngradeData } from './FeedbackDowngradeModal';
import { getShortPlan } from '../features/plan';
import { formatPlans } from './helpers';

const { MAIL, VPN } = PLAN_SERVICES;

interface Props extends Omit<ButtonProps, 'loading' | 'onClick'> {
    children: ReactNode;
}

const UnsubscribeButton = ({ className, children, ...rest }: Props) => {
    const [user] = useUser();
    const [subscription, loadingSubscription] = useSubscription();
    const [organization] = useOrganization();
    const [plans, loadingPlans] = usePlans();
    const [vpnCountries] = useVPNCountriesCount();
    const [vpnServers] = useVPNServersCount();
    const { createNotification, hideNotification } = useNotifications();
    const { createModal } = useModals();
    const api = useApi();
    const { call } = useEventManager();
    const [loading, withLoading] = useLoading();

    const { Plans = [], PeriodEnd = 0 } = subscription || {};
    const { plan } = formatPlans(Plans);

    const currentPlan = plan;
    const plansMap = toMap(plans, 'Name');

    const handleUnsubscribe = async (data: FeedbackDowngradeData) => {
        const downgradeNotificationId = createNotification({
            type: 'info',
            text: c('State').t`Downgrading your account, please wait`,
            expiration: 99999,
        });

        try {
            await api(deleteSubscription(data));
            await call();
            createNotification({ text: c('Success').t`You have successfully unsubscribed` });
        } finally {
            hideNotification(downgradeNotificationId);
        }
    };

    const handleClick = async () => {
        if (user.isFree) {
            return createNotification({ type: 'error', text: c('Info').t`You already have a free account` });
        }

        // Start promise early
        const calendarPromise = (async () => {
            const calendars: Calendar[] = await getCalendars(api);
            const personalCalendars = calendars.filter(unary(getIsPersonalCalendar));

            const hasLinks = !!(
                await Promise.all(
                    personalCalendars.map((calendar) => api<CalendarUrlsResponse>(getPublicLinks(calendar.ID)))
                )
            ).flatMap(({ CalendarUrls }) => CalendarUrls).length;

            return personalCalendars.length > MAX_CALENDARS_PER_FREE_USER || hasLinks;
        })();

        if (hasMigrationDiscount(subscription)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<DiscountWarningModal type="downgrade" onClose={reject} onConfirm={resolve} />);
            });
        }

        if (hasNewVisionary(subscription)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<NewVisionaryWarningModal type="downgrade" onClose={reject} onConfirm={resolve} />);
            });
        }

        const shortPlan = currentPlan
            ? getShortPlan(currentPlan.Name as PLANS, plansMap, vpnCountries, vpnServers)
            : undefined;
        // We only show the plan downgrade plan modal for plans that are defined with features
        if (shortPlan) {
            await new Promise<void>((resolve, reject) => {
                createModal(
                    <HighlightPlanDowngradeModal
                        shortPlan={shortPlan}
                        periodEnd={PeriodEnd}
                        onConfirm={resolve}
                        onClose={reject}
                    />
                );
            });
        }

        if (await calendarPromise) {
            await new Promise<void>((resolve, reject) => {
                createModal(<CalendarDowngradeModal onConfirm={reject} onClose={reject} />);
            });
        }

        if (hasBonuses(organization)) {
            await new Promise<void>((resolve, reject) => {
                createModal(<LossLoyaltyModal organization={organization} onConfirm={resolve} onClose={reject} />);
            });
        }

        if (organization.UsedMembers > 1) {
            await new Promise<void>((resolve, reject) => {
                createModal(<MemberDowngradeModal organization={organization} onConfirm={resolve} onClose={reject} />);
            });
        }

        const hasMail = hasBit(user.Subscribed, MAIL);
        const hasVpn = hasBit(user.Subscribed, VPN);

        if (hasMail || hasVpn) {
            await new Promise<void>((resolve, reject) => {
                createModal(<DowngradeModal hasMail={hasMail} hasVpn={hasVpn} onConfirm={resolve} onClose={reject} />);
            });
        }

        const data = await new Promise<FeedbackDowngradeData>((resolve, reject) => {
            createModal(<FeedbackDowngradeModal user={user} onSubmit={resolve} onClose={reject} />);
        });

        return handleUnsubscribe(data);
    };

    return (
        <Button
{'fraction_non_alphanumeric': 0.12250190694126621, 'fraction_numerical': 0.0010678871090770404, 'mean_word_length': 2.7332004555808656, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6021875', 'n_tokens_mistral': 3587, 'n_tokens_neox': 3496, 'n_words': 768}