✨ feat(subscribe): Add unsubscribe functionality with confirmation messages and localized strings
This commit is contained in:
parent
cc834caa30
commit
b2a2f42e53
@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
|
||||
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as announcement from './announcement';
|
||||
|
||||
@ -37,6 +37,7 @@ import { toast } from 'sonner';
|
||||
|
||||
import Renewal from '@/components/subscribe/renewal';
|
||||
import ResetTraffic from '@/components/subscribe/reset-traffic';
|
||||
import Unsubscribe from '@/components/subscribe/unsubscribe';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { getStat } from '@/services/common/common';
|
||||
import { getPlatform } from '@/utils/common';
|
||||
@ -145,12 +146,9 @@ export default function Content() {
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<ResetTraffic
|
||||
id={item.subscribe_id}
|
||||
token={item.token}
|
||||
replacement={item.subscribe.replacement}
|
||||
/>
|
||||
<Renewal token={item.token} subscribe={item.subscribe} />
|
||||
<ResetTraffic id={item.id} replacement={item.subscribe.replacement} />
|
||||
<Renewal id={item.id} subscribe={item.subscribe} />
|
||||
<Unsubscribe id={item.id} allowDeduction={item.subscribe.allow_deduction} />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
|
||||
@ -14,7 +14,7 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@workspace/ui/components/card';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { formatDate, isBrowser } from '@workspace/ui/utils';
|
||||
import { Copy } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
@ -60,19 +60,21 @@ export default function Affiliate() {
|
||||
<code className='bg-muted rounded px-2 py-1 text-2xl font-bold'>
|
||||
{user?.refer_code}
|
||||
</code>
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/auth?invite=${user?.refer_code}`}
|
||||
onCopy={(text, result) => {
|
||||
if (result) {
|
||||
toast.success(t('copySuccess'));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button variant='secondary' size='sm' className='gap-2'>
|
||||
<Copy className='h-4 w-4' />
|
||||
{t('copyInviteLink')}
|
||||
</Button>
|
||||
</CopyToClipboard>
|
||||
{isBrowser() && (
|
||||
<CopyToClipboard
|
||||
text={`${location?.origin}/auth?invite=${user?.refer_code}`}
|
||||
onCopy={(text, result) => {
|
||||
if (result) {
|
||||
toast.success(t('copySuccess'));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button variant='secondary' size='sm' className='gap-2'>
|
||||
<Copy className='h-4 w-4' />
|
||||
{t('copyInviteLink')}
|
||||
</Button>
|
||||
</CopyToClipboard>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@ -26,7 +26,7 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({ value, onChange }) => {
|
||||
return (
|
||||
<>
|
||||
<div className='font-semibold'>{t('paymentMethod')}</div>
|
||||
<RadioGroup className='mb-6 grid grid-cols-5 gap-2' value={value} onValueChange={onChange}>
|
||||
<RadioGroup className='grid grid-cols-5 gap-2' value={value} onValueChange={onChange}>
|
||||
{data?.map((item) => (
|
||||
<div key={item.mark}>
|
||||
<RadioGroupItem value={item.mark} id={item.mark} className='peer sr-only' />
|
||||
|
||||
@ -24,21 +24,20 @@ import { SubscribeBilling } from './billing';
|
||||
import { SubscribeDetail } from './detail';
|
||||
|
||||
interface RenewalProps {
|
||||
token: string;
|
||||
id: number;
|
||||
subscribe: API.Subscribe;
|
||||
}
|
||||
|
||||
export default function Renewal({ token, subscribe }: Readonly<RenewalProps>) {
|
||||
export default function Renewal({ id, subscribe }: Readonly<RenewalProps>) {
|
||||
const t = useTranslations('subscribe');
|
||||
const { getUserInfo } = useGlobalStore();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const router = useRouter();
|
||||
const [params, setParams] = useState<Partial<API.RenewalOrderRequest>>({
|
||||
quantity: 1,
|
||||
subscribe_id: subscribe.id,
|
||||
payment: 'balance',
|
||||
coupon: '',
|
||||
subscribe_token: token,
|
||||
user_subscribe_id: id,
|
||||
});
|
||||
const [loading, startTransition] = useTransition();
|
||||
|
||||
@ -55,15 +54,15 @@ export default function Renewal({ token, subscribe }: Readonly<RenewalProps>) {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (subscribe.id && token) {
|
||||
if (subscribe.id && id) {
|
||||
setParams((prev) => ({
|
||||
...prev,
|
||||
quantity: 1,
|
||||
subscribe_id: subscribe.id,
|
||||
subscribe_token: token,
|
||||
user_subscribe_id: id,
|
||||
}));
|
||||
}
|
||||
}, [subscribe.id, token]);
|
||||
}, [subscribe.id, id]);
|
||||
|
||||
const handleChange = useCallback((field: keyof typeof params, value: string | number) => {
|
||||
setParams((prev) => ({
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
import { Display } from '@/components/display';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { checkoutOrder, resetTraffic } from '@/services/user/order';
|
||||
import { getAvailablePaymentMethods } from '@/services/user/payment';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import {
|
||||
Dialog,
|
||||
@ -14,59 +12,43 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@workspace/ui/components/dialog';
|
||||
import { Label } from '@workspace/ui/components/label';
|
||||
import { RadioGroup, RadioGroupItem } from '@workspace/ui/components/radio-group';
|
||||
import { LoaderCircle } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Image from 'next/legacy/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState, useTransition } from 'react';
|
||||
import PaymentMethods from './payment-methods';
|
||||
|
||||
export default function ResetTraffic({
|
||||
id,
|
||||
token,
|
||||
replacement,
|
||||
}: {
|
||||
interface ResetTrafficProps {
|
||||
id: number;
|
||||
token: string;
|
||||
replacement?: number;
|
||||
}) {
|
||||
}
|
||||
export default function ResetTraffic({ id, replacement }: Readonly<ResetTrafficProps>) {
|
||||
const t = useTranslations('subscribe');
|
||||
const { getUserInfo } = useGlobalStore();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const router = useRouter();
|
||||
const [params, setParams] = useState<API.ResetTrafficOrderRequest>({
|
||||
subscribe_id: id,
|
||||
payment: 'balance',
|
||||
subscribe_token: token,
|
||||
user_subscribe_id: id,
|
||||
});
|
||||
const [loading, startTransition] = useTransition();
|
||||
|
||||
const { data: paymentMethods } = useQuery({
|
||||
queryKey: ['getAvailablePaymentMethods'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getAvailablePaymentMethods();
|
||||
return data.data?.list || [];
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (id && token) {
|
||||
if (id) {
|
||||
setParams((prev) => ({
|
||||
...prev,
|
||||
quantity: 1,
|
||||
subscribe_id: id,
|
||||
subscribe_token: token,
|
||||
user_subscribe_id: id,
|
||||
}));
|
||||
}
|
||||
}, [id, token]);
|
||||
}, [id]);
|
||||
|
||||
if (!replacement) return;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant='outline' size='sm'>
|
||||
<Button variant='secondary' size='sm'>
|
||||
{t('resetTraffic')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
@ -83,41 +65,15 @@ export default function ResetTraffic({
|
||||
<Display type='currency' value={replacement} />
|
||||
</span>
|
||||
</div>
|
||||
<div className='font-semibold'>{t('paymentMethod')}</div>
|
||||
<RadioGroup
|
||||
className='grid grid-cols-5 gap-2'
|
||||
<PaymentMethods
|
||||
value={params.payment}
|
||||
onValueChange={(value) => {
|
||||
onChange={(value) => {
|
||||
setParams({
|
||||
...params,
|
||||
payment: value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{paymentMethods?.map((item) => {
|
||||
return (
|
||||
<div key={item.mark}>
|
||||
<RadioGroupItem value={item.mark} id={item.mark} className='peer sr-only' />
|
||||
<Label
|
||||
htmlFor={item.mark}
|
||||
className='border-muted bg-popover hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary flex flex-col items-center justify-between rounded-md border-2 py-2'
|
||||
>
|
||||
<div className='mb-3 size-12'>
|
||||
<Image
|
||||
src={item.icon || `/payment/${item.mark}.svg`}
|
||||
width={48}
|
||||
height={48}
|
||||
alt={item.name!}
|
||||
/>
|
||||
</div>
|
||||
<span className='w-full overflow-hidden text-ellipsis whitespace-nowrap text-center'>
|
||||
{item.name || t(`methods.${item.mark}`)}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</RadioGroup>
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className='fixed bottom-0 left-0 w-full rounded-none md:relative md:mt-6'
|
||||
|
||||
84
apps/user/components/subscribe/unsubscribe.tsx
Normal file
84
apps/user/components/subscribe/unsubscribe.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
'use client';
|
||||
|
||||
import { preUnsubscribe, unsubscribe } from '@/services/user/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@workspace/ui/components/dialog';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Display } from '../display';
|
||||
|
||||
interface UnsubscribeProps {
|
||||
id: number;
|
||||
allowDeduction?: boolean;
|
||||
}
|
||||
|
||||
export default function Unsubscribe({ id, allowDeduction }: Readonly<UnsubscribeProps>) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const router = useRouter();
|
||||
const t = useTranslations('subscribe.unsubscribe');
|
||||
|
||||
const { data } = useQuery({
|
||||
enabled: Boolean(open && id && allowDeduction),
|
||||
queryKey: ['preUnsubscribe', id],
|
||||
queryFn: async () => {
|
||||
const { data } = await preUnsubscribe({ id });
|
||||
return data.data?.deduction_amount;
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await unsubscribe(
|
||||
{ id },
|
||||
{
|
||||
skipErrorHandler: true,
|
||||
},
|
||||
);
|
||||
toast.success(t('success'));
|
||||
router.refresh();
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
toast.error(t('failed'));
|
||||
}
|
||||
};
|
||||
|
||||
if (!allowDeduction) return null;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant='destructive' size='sm'>
|
||||
{t('unsubscribe')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('confirmUnsubscribe')}</DialogTitle>
|
||||
<DialogDescription>{t('confirmUnsubscribeDescription')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<p>{t('availableDeductionAmount')}</p>
|
||||
<p className='text-primary text-2xl font-semibold'>
|
||||
<Display type='currency' value={data} />
|
||||
</p>
|
||||
<p className='text-muted-foreground text-sm'>{t('deductionNote')}</p>
|
||||
<DialogFooter>
|
||||
<Button variant='outline' onClick={() => setOpen(false)}>
|
||||
{t('cancel')}
|
||||
</Button>
|
||||
<Button onClick={handleSubmit}>{t('confirm')}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Obnovit předplatné",
|
||||
"resetPrice": "Obnovit cenu",
|
||||
"resetTraffic": "Obnovit provoz",
|
||||
"resetTrafficDescription": "Obnovit provoz pouze pro aktuální měsíc",
|
||||
"resetTrafficTitle": "Obnovit provoz"
|
||||
"resetTrafficDescription": "Obnovit provoz na nulu a zahájit nový fakturační cyklus",
|
||||
"resetTrafficTitle": "Obnovit provoz",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Dostupná částka k odečtení:",
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"confirmUnsubscribe": "Potvrdit odhlášení",
|
||||
"confirmUnsubscribeDescription": "Opravdu se chcete odhlásit z odběru?",
|
||||
"deductionNote": "Upozornění: Pokud se nyní odhlásíte, zbývající hodnota vašeho předplatného bude vrácena jako odpočitatelný zůstatek na váš účet, který můžete použít při dalším nákupu nebo obnovení předplatného.",
|
||||
"failed": "Nepodařilo se odhlásit z odběru. Zkuste to prosím znovu.",
|
||||
"success": "Úspěšně jste se odhlásili z odběru.",
|
||||
"unsubscribe": "Odhlásit odběr"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Abonnement erneuern",
|
||||
"resetPrice": "Preis zurücksetzen",
|
||||
"resetTraffic": "Datenverkehr zurücksetzen",
|
||||
"resetTrafficDescription": "Verkehr nur für den aktuellen Monat zurücksetzen",
|
||||
"resetTrafficTitle": "Datenverkehr zurücksetzen"
|
||||
"resetTrafficDescription": "Setzen Sie den Datenverkehr auf null zurück und starten Sie einen neuen Abrechnungszyklus",
|
||||
"resetTrafficTitle": "Datenverkehr zurücksetzen",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Verfügbarer Abzugsbetrag:",
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmUnsubscribe": "Abbestellung bestätigen",
|
||||
"confirmUnsubscribeDescription": "Sind Sie sicher, dass Sie abbestellen möchten?",
|
||||
"deductionNote": "Bitte beachten Sie: Wenn Sie jetzt kündigen, wird der verbleibende Wert Ihres Abonnements als abzugsfähiges Guthaben auf Ihr Konto zurückerstattet, das für Ihren nächsten Abonnementkauf oder die Verlängerung verwendet werden kann.",
|
||||
"failed": "Abbestellung fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"success": "Sie wurden erfolgreich abbestellt.",
|
||||
"unsubscribe": "Abbestellen"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Renew Subscription",
|
||||
"resetPrice": "Reset Price",
|
||||
"resetTraffic": "Reset Traffic",
|
||||
"resetTrafficDescription": "Reset traffic for the current month only",
|
||||
"resetTrafficTitle": "Reset Traffic"
|
||||
"resetTrafficDescription": "Reset traffic to zero, and start a new billing cycle",
|
||||
"resetTrafficTitle": "Reset Traffic",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Available deduction amount:",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmUnsubscribe": "Confirm Unsubscribe",
|
||||
"confirmUnsubscribeDescription": "Are you sure you want to unsubscribe?",
|
||||
"deductionNote": "Please note: If you unsubscribe now, the remaining value of your subscription will be refunded as a deductible balance to your account, which can be used for your next subscription purchase or renewal.",
|
||||
"failed": "Failed to unsubscribe. Please try again.",
|
||||
"success": "You have been unsubscribed successfully.",
|
||||
"unsubscribe": "Unsubscribe"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Renovar suscripción",
|
||||
"resetPrice": "Restablecer Precio",
|
||||
"resetTraffic": "Restablecer Tráfico",
|
||||
"resetTrafficDescription": "Restablecer el tráfico solo para el mes actual",
|
||||
"resetTrafficTitle": "Restablecer Tráfico"
|
||||
"resetTrafficDescription": "Restablecer el tráfico a cero y comenzar un nuevo ciclo de facturación",
|
||||
"resetTrafficTitle": "Restablecer Tráfico",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Monto de deducción disponible:",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmUnsubscribe": "Confirmar baja",
|
||||
"confirmUnsubscribeDescription": "¿Está seguro de que desea darse de baja?",
|
||||
"deductionNote": "Por favor, tenga en cuenta: Si se da de baja ahora, el valor restante de su suscripción se reembolsará como un saldo deducible en su cuenta, que podrá utilizar para su próxima compra o renovación de suscripción.",
|
||||
"failed": "No se pudo dar de baja. Por favor, inténtelo de nuevo.",
|
||||
"success": "Se ha dado de baja con éxito.",
|
||||
"unsubscribe": "Darse de baja"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Renovar Suscripción",
|
||||
"resetPrice": "Restablecer Precio",
|
||||
"resetTraffic": "Restablecer Tráfico",
|
||||
"resetTrafficDescription": "Restablecer el tráfico solo para el mes actual",
|
||||
"resetTrafficTitle": "Restablecer Tráfico"
|
||||
"resetTrafficDescription": "Restablecer el tráfico a cero y comenzar un nuevo ciclo de facturación",
|
||||
"resetTrafficTitle": "Restablecer Tráfico",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Monto de deducción disponible:",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmUnsubscribe": "Confirmar baja",
|
||||
"confirmUnsubscribeDescription": "¿Estás seguro de que deseas darte de baja?",
|
||||
"deductionNote": "Por favor, tenga en cuenta: Si se da de baja ahora, el valor restante de su suscripción se reembolsará como un saldo deducible en su cuenta, que podrá utilizar para su próxima compra o renovación de suscripción.",
|
||||
"failed": "Error al darse de baja. Por favor, inténtalo de nuevo.",
|
||||
"success": "Te has dado de baja exitosamente.",
|
||||
"unsubscribe": "Darse de baja"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "تمدید اشتراک",
|
||||
"resetPrice": "بازنشانی قیمت",
|
||||
"resetTraffic": "بازنشانی ترافیک",
|
||||
"resetTrafficDescription": "بازنشانی ترافیک فقط برای ماه جاری",
|
||||
"resetTrafficTitle": "بازنشانی ترافیک"
|
||||
"resetTrafficDescription": "ترافیک را به صفر بازنشانی کنید و یک دوره صورتحساب جدید را شروع کنید",
|
||||
"resetTrafficTitle": "بازنشانی ترافیک",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "مبلغ کسر موجود:",
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"confirmUnsubscribe": "تأیید لغو اشتراک",
|
||||
"confirmUnsubscribeDescription": "آیا مطمئن هستید که میخواهید اشتراک خود را لغو کنید؟",
|
||||
"deductionNote": "لطفاً توجه داشته باشید: اگر اکنون لغو اشتراک کنید، ارزش باقیمانده اشتراک شما به عنوان یک موجودی قابل کسر به حساب شما بازگردانده میشود که میتواند برای خرید یا تمدید اشتراک بعدی شما استفاده شود.",
|
||||
"failed": "لغو اشتراک ناموفق بود. لطفاً دوباره تلاش کنید.",
|
||||
"success": "اشتراک شما با موفقیت لغو شد.",
|
||||
"unsubscribe": "لغو اشتراک"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Uudista tilaus",
|
||||
"resetPrice": "Nollaa hinta",
|
||||
"resetTraffic": "Nollaa liikenne",
|
||||
"resetTrafficDescription": "Nollaa liikenne vain kuluvan kuukauden osalta",
|
||||
"resetTrafficTitle": "Nollaa liikenne"
|
||||
"resetTrafficDescription": "Nollaa liikenne ja aloita uusi laskutusjakso",
|
||||
"resetTrafficTitle": "Nollaa liikenne",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Käytettävissä oleva vähennysmäärä:",
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"confirmUnsubscribe": "Vahvista tilauksen peruutus",
|
||||
"confirmUnsubscribeDescription": "Oletko varma, että haluat peruuttaa tilauksen?",
|
||||
"deductionNote": "Huomioithan: Jos peruutat tilauksesi nyt, jäljellä oleva tilauksesi arvo hyvitetään vähennettävänä saldona tilillesi, jota voit käyttää seuraavan tilauksen ostoon tai uusimiseen.",
|
||||
"failed": "Tilauksen peruutus epäonnistui. Yritä uudelleen.",
|
||||
"success": "Olet peruuttanut tilauksen onnistuneesti.",
|
||||
"unsubscribe": "Peruuta tilaus"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Renouveler l'abonnement",
|
||||
"resetPrice": "Réinitialiser le prix",
|
||||
"resetTraffic": "Réinitialiser le trafic",
|
||||
"resetTrafficDescription": "Réinitialiser le trafic pour le mois en cours uniquement",
|
||||
"resetTrafficTitle": "Réinitialiser le trafic"
|
||||
"resetTrafficDescription": "Réinitialiser le trafic à zéro et commencer un nouveau cycle de facturation",
|
||||
"resetTrafficTitle": "Réinitialiser le trafic",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Montant de la déduction disponible :",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"confirmUnsubscribe": "Confirmer le désabonnement",
|
||||
"confirmUnsubscribeDescription": "Êtes-vous sûr de vouloir vous désabonner ?",
|
||||
"deductionNote": "Veuillez noter : Si vous vous désabonnez maintenant, la valeur restante de votre abonnement sera remboursée sous forme de solde déductible sur votre compte, qui pourra être utilisé pour votre prochain achat ou renouvellement d'abonnement.",
|
||||
"failed": "Échec du désabonnement. Veuillez réessayer.",
|
||||
"success": "Vous vous êtes désabonné avec succès.",
|
||||
"unsubscribe": "Se désabonner"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "सदस्यता नवीनीकरण करें",
|
||||
"resetPrice": "मूल्य रीसेट करें",
|
||||
"resetTraffic": "ट्रैफ़िक रीसेट करें",
|
||||
"resetTrafficDescription": "केवल वर्तमान माह के लिए ट्रैफिक रीसेट करें",
|
||||
"resetTrafficTitle": "ट्रैफ़िक रीसेट करें"
|
||||
"resetTrafficDescription": "ट्रैफ़िक को शून्य पर रीसेट करें, और एक नया बिलिंग चक्र शुरू करें",
|
||||
"resetTrafficTitle": "ट्रैफ़िक रीसेट करें",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "उपलब्ध कटौती राशि:",
|
||||
"cancel": "रद्द करें",
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmUnsubscribe": "सदस्यता समाप्ति की पुष्टि करें",
|
||||
"confirmUnsubscribeDescription": "क्या आप वाकई सदस्यता समाप्त करना चाहते हैं?",
|
||||
"deductionNote": "कृपया ध्यान दें: यदि आप अभी सदस्यता समाप्त करते हैं, तो आपकी सदस्यता के शेष मूल्य को आपके खाते में एक कटौती योग्य शेष राशि के रूप में वापस कर दिया जाएगा, जिसका उपयोग आप अपनी अगली सदस्यता खरीद या नवीनीकरण के लिए कर सकते हैं।",
|
||||
"failed": "सदस्यता समाप्त करने में विफल। कृपया पुनः प्रयास करें।",
|
||||
"success": "आपकी सदस्यता सफलतापूर्वक समाप्त कर दी गई है।",
|
||||
"unsubscribe": "सदस्यता समाप्त करें"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Előfizetés megújítása",
|
||||
"resetPrice": "Ár visszaállítása",
|
||||
"resetTraffic": "Forgalom visszaállítása",
|
||||
"resetTrafficDescription": "Forgalmi adatok visszaállítása csak az aktuális hónapra",
|
||||
"resetTrafficTitle": "Forgalom visszaállítása"
|
||||
"resetTrafficDescription": "Forgalmi adatok nullázása és új számlázási ciklus indítása",
|
||||
"resetTrafficTitle": "Forgalom visszaállítása",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Elérhető levonási összeg:",
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősít",
|
||||
"confirmUnsubscribe": "Leiratkozás megerősítése",
|
||||
"confirmUnsubscribeDescription": "Biztosan le szeretne iratkozni?",
|
||||
"deductionNote": "Kérjük, vegye figyelembe: Ha most leiratkozik, az előfizetése fennmaradó értéke levonható egyenlegként kerül visszatérítésre a fiókjába, amelyet a következő előfizetés vásárlására vagy megújítására használhat fel.",
|
||||
"failed": "A leiratkozás nem sikerült. Kérjük, próbálja újra.",
|
||||
"success": "Sikeresen leiratkozott.",
|
||||
"unsubscribe": "Leiratkozás"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "サブスクリプションを更新する",
|
||||
"resetPrice": "価格をリセット",
|
||||
"resetTraffic": "トラフィックをリセット",
|
||||
"resetTrafficDescription": "今月のみのトラフィックをリセットする",
|
||||
"resetTrafficTitle": "トラフィックをリセット"
|
||||
"resetTrafficDescription": "トラフィックをゼロにリセットし、新しい請求サイクルを開始します",
|
||||
"resetTrafficTitle": "トラフィックをリセット",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "利用可能な控除額:",
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
"confirmUnsubscribe": "購読解除を確認",
|
||||
"confirmUnsubscribeDescription": "本当に購読を解除しますか?",
|
||||
"deductionNote": "ご注意ください: 今すぐに退会される場合、残りのサブスクリプションの価値は控除可能な残高としてアカウントに返金され、次回のサブスクリプション購入または更新に使用できます。",
|
||||
"failed": "購読解除に失敗しました。もう一度お試しください。",
|
||||
"success": "購読解除が成功しました。",
|
||||
"unsubscribe": "購読解除"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "구독 갱신",
|
||||
"resetPrice": "가격 재설정",
|
||||
"resetTraffic": "트래픽 재설정",
|
||||
"resetTrafficDescription": "현재 월에 대한 트래픽만 재설정",
|
||||
"resetTrafficTitle": "트래픽 재설정"
|
||||
"resetTrafficDescription": "트래픽을 0으로 재설정하고 새로운 청구 주기를 시작합니다",
|
||||
"resetTrafficTitle": "트래픽 재설정",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "사용 가능한 공제 금액:",
|
||||
"cancel": "취소",
|
||||
"confirm": "확인",
|
||||
"confirmUnsubscribe": "구독 취소 확인",
|
||||
"confirmUnsubscribeDescription": "정말로 구독을 취소하시겠습니까?",
|
||||
"deductionNote": "참고: 지금 구독을 취소하시면, 구독의 남은 금액이 계정에 공제 가능한 잔액으로 환불되며, 이는 다음 구독 구매나 갱신 시 사용할 수 있습니다.",
|
||||
"failed": "구독 취소에 실패했습니다. 다시 시도해 주세요.",
|
||||
"success": "성공적으로 구독이 취소되었습니다.",
|
||||
"unsubscribe": "구독 취소"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Forny abonnement",
|
||||
"resetPrice": "Tilbakestill pris",
|
||||
"resetTraffic": "Tilbakestill trafikk",
|
||||
"resetTrafficDescription": "Tilbakestill trafikk kun for inneværende måned",
|
||||
"resetTrafficTitle": "Nullstill trafikk"
|
||||
"resetTrafficDescription": "Nullstill trafikk til null, og start en ny faktureringssyklus",
|
||||
"resetTrafficTitle": "Nullstill trafikk",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Tilgjengelig fradragsbeløp:",
|
||||
"cancel": "Avbryt",
|
||||
"confirm": "Bekreft",
|
||||
"confirmUnsubscribe": "Bekreft avslutning av abonnement",
|
||||
"confirmUnsubscribeDescription": "Er du sikker på at du vil avslutte abonnementet?",
|
||||
"deductionNote": "Vennligst merk: Hvis du avslutter abonnementet nå, vil den gjenværende verdien av abonnementet ditt bli refundert som en fradragsberettiget saldo til kontoen din, som kan brukes til ditt neste abonnementskjøp eller fornyelse.",
|
||||
"failed": "Kunne ikke avslutte abonnementet. Vennligst prøv igjen.",
|
||||
"success": "Du har blitt avmeldt abonnementet vellykket.",
|
||||
"unsubscribe": "Avslutt abonnement"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Odnów subskrypcję",
|
||||
"resetPrice": "Zresetuj cenę",
|
||||
"resetTraffic": "Zresetuj ruch",
|
||||
"resetTrafficDescription": "Zresetuj ruch tylko na bieżący miesiąc",
|
||||
"resetTrafficTitle": "Zresetuj Ruch"
|
||||
"resetTrafficDescription": "Zresetuj ruch do zera i rozpocznij nowy cykl rozliczeniowy",
|
||||
"resetTrafficTitle": "Zresetuj Ruch",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Dostępna kwota odliczenia:",
|
||||
"cancel": "Anuluj",
|
||||
"confirm": "Potwierdź",
|
||||
"confirmUnsubscribe": "Potwierdź anulowanie subskrypcji",
|
||||
"confirmUnsubscribeDescription": "Czy na pewno chcesz anulować subskrypcję?",
|
||||
"deductionNote": "Proszę zauważyć: Jeśli teraz zrezygnujesz z subskrypcji, pozostała wartość Twojej subskrypcji zostanie zwrócona jako saldo do odliczenia na Twoim koncie, które można wykorzystać przy następnym zakupie lub odnowieniu subskrypcji.",
|
||||
"failed": "Nie udało się anulować subskrypcji. Spróbuj ponownie.",
|
||||
"success": "Subskrypcja została pomyślnie anulowana.",
|
||||
"unsubscribe": "Anuluj subskrypcję"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Renovar Assinatura",
|
||||
"resetPrice": "Redefinir Preço",
|
||||
"resetTraffic": "Redefinir Tráfego",
|
||||
"resetTrafficDescription": "Redefinir o tráfego apenas para o mês atual",
|
||||
"resetTrafficTitle": "Redefinir Tráfego"
|
||||
"resetTrafficDescription": "Redefinir o tráfego para zero e iniciar um novo ciclo de faturamento",
|
||||
"resetTrafficTitle": "Redefinir Tráfego",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Valor disponível para dedução:",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmUnsubscribe": "Confirmar cancelamento",
|
||||
"confirmUnsubscribeDescription": "Tem certeza de que deseja cancelar a inscrição?",
|
||||
"deductionNote": "Por favor, note: Se você cancelar a assinatura agora, o valor restante da sua assinatura será reembolsado como um saldo dedutível na sua conta, que pode ser usado para sua próxima compra ou renovação de assinatura.",
|
||||
"failed": "Falha ao cancelar a inscrição. Por favor, tente novamente.",
|
||||
"success": "Você cancelou a inscrição com sucesso.",
|
||||
"unsubscribe": "Cancelar inscrição"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Reînnoiește Abonamentul",
|
||||
"resetPrice": "Resetează Prețul",
|
||||
"resetTraffic": "Resetează Traficul",
|
||||
"resetTrafficDescription": "Resetează traficul doar pentru luna curentă",
|
||||
"resetTrafficTitle": "Resetează Traficul"
|
||||
"resetTrafficDescription": "Resetați traficul la zero și începeți un nou ciclu de facturare",
|
||||
"resetTrafficTitle": "Resetează Traficul",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Suma disponibilă pentru deducere:",
|
||||
"cancel": "Anulează",
|
||||
"confirm": "Confirmă",
|
||||
"confirmUnsubscribe": "Confirmă Dezabonarea",
|
||||
"confirmUnsubscribeDescription": "Ești sigur că vrei să te dezabonezi?",
|
||||
"deductionNote": "Vă rugăm să rețineți: Dacă vă dezabonați acum, valoarea rămasă a abonamentului dumneavoastră va fi rambursată ca un sold deductibil în contul dumneavoastră, care poate fi utilizat pentru următoarea achiziție sau reînnoire a abonamentului.",
|
||||
"failed": "Dezabonarea a eșuat. Te rugăm să încerci din nou.",
|
||||
"success": "Te-ai dezabonat cu succes.",
|
||||
"unsubscribe": "Dezabonare"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Продлить подписку",
|
||||
"resetPrice": "Сбросить цену",
|
||||
"resetTraffic": "Сбросить трафик",
|
||||
"resetTrafficDescription": "Сбросить трафик только за текущий месяц",
|
||||
"resetTrafficTitle": "Сбросить трафик"
|
||||
"resetTrafficDescription": "Сбросить трафик до нуля и начать новый расчетный период",
|
||||
"resetTrafficTitle": "Сбросить трафик",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Доступная сумма вычета:",
|
||||
"cancel": "Отмена",
|
||||
"confirm": "Подтвердить",
|
||||
"confirmUnsubscribe": "Подтвердить отписку",
|
||||
"confirmUnsubscribeDescription": "Вы уверены, что хотите отписаться?",
|
||||
"deductionNote": "Пожалуйста, обратите внимание: если вы откажетесь от подписки сейчас, оставшаяся стоимость вашей подписки будет возвращена в виде вычитаемого баланса на ваш счет, который можно использовать для следующей покупки или продления подписки.",
|
||||
"failed": "Не удалось отписаться. Пожалуйста, попробуйте еще раз.",
|
||||
"success": "Вы успешно отписались.",
|
||||
"unsubscribe": "Отписаться"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "ต่ออายุการสมัครสมาชิก",
|
||||
"resetPrice": "รีเซ็ตราคา",
|
||||
"resetTraffic": "รีเซ็ตการจราจร",
|
||||
"resetTrafficDescription": "รีเซ็ตการใช้งานข้อมูลสำหรับเดือนปัจจุบันเท่านั้น",
|
||||
"resetTrafficTitle": "รีเซ็ตการจราจร"
|
||||
"resetTrafficDescription": "รีเซ็ตการใช้งานข้อมูลให้เป็นศูนย์ และเริ่มรอบบิลใหม่",
|
||||
"resetTrafficTitle": "รีเซ็ตการจราจร",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "จำนวนเงินที่หักได้:",
|
||||
"cancel": "ยกเลิก",
|
||||
"confirm": "ยืนยัน",
|
||||
"confirmUnsubscribe": "ยืนยันการยกเลิกการสมัคร",
|
||||
"confirmUnsubscribeDescription": "คุณแน่ใจหรือว่าต้องการยกเลิกการสมัคร?",
|
||||
"deductionNote": "โปรดทราบ: หากคุณยกเลิกการสมัครสมาชิกตอนนี้ มูลค่าที่เหลือของการสมัครสมาชิกของคุณจะถูกคืนเป็นยอดคงเหลือที่หักได้ในบัญชีของคุณ ซึ่งสามารถใช้สำหรับการซื้อหรือการต่ออายุการสมัครสมาชิกครั้งถัดไปของคุณได้",
|
||||
"failed": "การยกเลิกการสมัครล้มเหลว กรุณาลองใหม่อีกครั้ง",
|
||||
"success": "คุณได้ยกเลิกการสมัครเรียบร้อยแล้ว",
|
||||
"unsubscribe": "ยกเลิกการสมัคร"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Aboneliği Yenile",
|
||||
"resetPrice": "Fiyatı Sıfırla",
|
||||
"resetTraffic": "Trafiği Sıfırla",
|
||||
"resetTrafficDescription": "Yalnızca mevcut ay için trafiği sıfırla",
|
||||
"resetTrafficTitle": "Trafiği Sıfırla"
|
||||
"resetTrafficDescription": "Trafiği sıfırlayın ve yeni bir faturalama döngüsü başlatın",
|
||||
"resetTrafficTitle": "Trafiği Sıfırla",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Kullanılabilir indirim tutarı:",
|
||||
"cancel": "İptal",
|
||||
"confirm": "Onayla",
|
||||
"confirmUnsubscribe": "Abonelikten Çıkmayı Onayla",
|
||||
"confirmUnsubscribeDescription": "Abonelikten çıkmak istediğinizden emin misiniz?",
|
||||
"deductionNote": "Lütfen dikkat: Şimdi abonelikten çıkarsanız, aboneliğinizin kalan değeri hesabınıza indirilebilir bir bakiye olarak iade edilecektir. Bu bakiye, bir sonraki abonelik satın alımınızda veya yenilemenizde kullanılabilir.",
|
||||
"failed": "Abonelikten çıkılamadı. Lütfen tekrar deneyin.",
|
||||
"success": "Başarıyla abonelikten çıktınız.",
|
||||
"unsubscribe": "Abonelikten Çık"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Поновити підписку",
|
||||
"resetPrice": "Скинути ціну",
|
||||
"resetTraffic": "Скинути трафік",
|
||||
"resetTrafficDescription": "Скинути трафік лише для поточного місяця",
|
||||
"resetTrafficTitle": "Скинути трафік"
|
||||
"resetTrafficDescription": "Скинути трафік до нуля та розпочати новий білінговий цикл",
|
||||
"resetTrafficTitle": "Скинути трафік",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Доступна сума відрахування:",
|
||||
"cancel": "Скасувати",
|
||||
"confirm": "Підтвердити",
|
||||
"confirmUnsubscribe": "Підтвердити відписку",
|
||||
"confirmUnsubscribeDescription": "Ви впевнені, що хочете відписатися?",
|
||||
"deductionNote": "Зверніть увагу: Якщо ви відмовитеся від підписки зараз, залишкова вартість вашої підписки буде повернена як відраховуваний баланс на ваш рахунок, який можна використати для наступної покупки або поновлення підписки.",
|
||||
"failed": "Не вдалося відписатися. Будь ласка, спробуйте ще раз.",
|
||||
"success": "Ви успішно відписалися.",
|
||||
"unsubscribe": "Відписатися"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "Gia hạn đăng ký",
|
||||
"resetPrice": "Đặt lại giá",
|
||||
"resetTraffic": "Đặt lại Lưu lượng",
|
||||
"resetTrafficDescription": "Đặt lại lưu lượng truy cập chỉ cho tháng hiện tại",
|
||||
"resetTrafficTitle": "Đặt lại Lưu lượng"
|
||||
"resetTrafficDescription": "Đặt lại lưu lượng về không và bắt đầu chu kỳ thanh toán mới",
|
||||
"resetTrafficTitle": "Đặt lại Lưu lượng",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "Số tiền khấu trừ có sẵn:",
|
||||
"cancel": "Hủy bỏ",
|
||||
"confirm": "Xác nhận",
|
||||
"confirmUnsubscribe": "Xác nhận hủy đăng ký",
|
||||
"confirmUnsubscribeDescription": "Bạn có chắc chắn muốn hủy đăng ký không?",
|
||||
"deductionNote": "Xin lưu ý: Nếu bạn hủy đăng ký ngay bây giờ, giá trị còn lại của đăng ký sẽ được hoàn trả dưới dạng số dư có thể khấu trừ vào tài khoản của bạn, số dư này có thể được sử dụng cho lần mua hoặc gia hạn đăng ký tiếp theo.",
|
||||
"failed": "Hủy đăng ký không thành công. Vui lòng thử lại.",
|
||||
"success": "Bạn đã hủy đăng ký thành công.",
|
||||
"unsubscribe": "Hủy đăng ký"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "续订",
|
||||
"resetPrice": "重置价格",
|
||||
"resetTraffic": "重置流量",
|
||||
"resetTrafficDescription": "仅重置本月的流量",
|
||||
"resetTrafficTitle": "重置流量"
|
||||
"resetTrafficDescription": "将流量重置为零,并开始新的计费周期",
|
||||
"resetTrafficTitle": "重置流量",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "可用扣减金额:",
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
"confirmUnsubscribe": "确认取消订阅",
|
||||
"confirmUnsubscribeDescription": "您确定要取消订阅吗?",
|
||||
"deductionNote": "请注意:如果您现在取消订阅,订阅剩余价值将作为可扣减余额退还到您的账户中,可用于下次订阅购买或续订。",
|
||||
"failed": "取消订阅失败。请重试。",
|
||||
"success": "您已成功取消订阅。",
|
||||
"unsubscribe": "取消订阅"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,17 @@
|
||||
"renewSubscription": "續訂",
|
||||
"resetPrice": "重設價格",
|
||||
"resetTraffic": "重設流量",
|
||||
"resetTrafficDescription": "僅重設本月的流量",
|
||||
"resetTrafficTitle": "重設流量"
|
||||
"resetTrafficDescription": "重設流量至零,並開始新的計費週期",
|
||||
"resetTrafficTitle": "重設流量",
|
||||
"unsubscribe": {
|
||||
"availableDeductionAmount": "可扣除金額:",
|
||||
"cancel": "取消",
|
||||
"confirm": "確認",
|
||||
"confirmUnsubscribe": "確認取消訂閱",
|
||||
"confirmUnsubscribeDescription": "您確定要取消訂閱嗎?",
|
||||
"deductionNote": "請注意:如果您現在取消訂閱,訂閱的剩餘價值將以可扣減餘額的形式退還到您的帳戶,您可以用於下次訂閱購買或續訂。",
|
||||
"failed": "取消訂閱失敗。請再試一次。",
|
||||
"success": "您已成功取消訂閱。",
|
||||
"unsubscribe": "取消訂閱"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user