diff --git a/packages/console/src/hooks/use-subscribe.ts b/packages/console/src/hooks/use-subscribe.ts index 27ac6bc5f..0009d0176 100644 --- a/packages/console/src/hooks/use-subscribe.ts +++ b/packages/console/src/hooks/use-subscribe.ts @@ -1,10 +1,17 @@ +import dayjs from 'dayjs'; import { nanoid } from 'nanoid'; +import { useContext } from 'react'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import { toastResponseError, useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { type CreateTenantData } from '@/components/CreateTenantModal/type'; -import { checkoutStateQueryKey, checkoutSuccessCallbackPath } from '@/consts/subscriptions'; +import { + ReservedPlanId, + checkoutStateQueryKey, + checkoutSuccessCallbackPath, +} from '@/consts/subscriptions'; +import { TenantsContext } from '@/contexts/TenantsProvider'; import { createLocalCheckoutSession } from '@/utils/checkout'; import useTenantPathname from './use-tenant-pathname'; @@ -18,8 +25,9 @@ type SubscribeProps = { }; const useSubscribe = () => { - const cloudApi = useCloudApi({ hideErrorToast: true }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const cloudApi = useCloudApi({ hideErrorToast: true }); + const { updateTenant } = useContext(TenantsContext); const { getUrl } = useTenantPathname(); const subscribe = async ({ @@ -70,6 +78,20 @@ const useSubscribe = () => { tenantId, }, }); + + /** + * Note: need to update the tenant's subscription cache data, + * since the cancel subscription flow will not redirect to the stripe payment page. + */ + updateTenant(tenantId, { + planId: ReservedPlanId.free, + subscription: { + status: 'active', + planId: ReservedPlanId.free, + currentPeriodStart: dayjs().toDate(), + currentPeriodEnd: dayjs().add(1, 'month').toDate(), + }, + }); }; const visitManagePaymentPage = async (tenantId: string) => { diff --git a/packages/console/src/pages/TenantSettings/TenantBasicSettings/index.tsx b/packages/console/src/pages/TenantSettings/TenantBasicSettings/index.tsx index c9da52ffc..c160bc83d 100644 --- a/packages/console/src/pages/TenantSettings/TenantBasicSettings/index.tsx +++ b/packages/console/src/pages/TenantSettings/TenantBasicSettings/index.tsx @@ -7,11 +7,13 @@ import { useTranslation } from 'react-i18next'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { type TenantResponse } from '@/cloud/types/router'; -import AppError from '@/components/AppError'; import PageMeta from '@/components/PageMeta'; import SubmitFormChangesActionBar from '@/components/SubmitFormChangesActionBar'; import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal'; +import { ReservedPlanId } from '@/consts/subscriptions'; import { TenantsContext } from '@/contexts/TenantsProvider'; +import { useConfirmModal } from '@/hooks/use-confirm-modal'; +import { trySubmitSafe } from '@/utils/form'; import DeleteCard from './DeleteCard'; import DeleteModal from './DeleteModal'; @@ -28,12 +30,12 @@ const tenantProfileToForm = (tenant?: TenantResponse): TenantSettingsForm => { function TenantBasicSettings() { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const api = useCloudApi({ hideErrorToast: true }); + const api = useCloudApi(); const { currentTenant, currentTenantId, updateTenant, removeTenant, navigateTenant } = useContext(TenantsContext); - const [error, setError] = useState(); const [isDeletionModalOpen, setIsDeletionModalOpen] = useState(false); const [isDeleting, setIsDeleting] = useState(false); + const { show: showModal } = useConfirmModal(); const methods = useForm({ defaultValues: tenantProfileToForm(currentTenant), @@ -50,35 +52,43 @@ function TenantBasicSettings() { }, [currentTenant, reset]); const saveData = async (data: { name?: string; tag?: TenantTag }) => { - try { - const { name, tag } = await api.patch(`/api/tenants/:tenantId`, { - params: { tenantId: currentTenantId }, - body: data, - }); - reset({ profile: { name, tag } }); - toast.success(t('tenants.settings.tenant_info_saved')); - updateTenant(currentTenantId, data); - } catch (error: unknown) { - setError( - error instanceof Error - ? error - : new Error(JSON.stringify(error, Object.getOwnPropertyNames(error))) - ); - } + const { name, tag } = await api.patch(`/api/tenants/:tenantId`, { + params: { tenantId: currentTenantId }, + body: data, + }); + reset({ profile: { name, tag } }); + toast.success(t('tenants.settings.tenant_info_saved')); + updateTenant(currentTenantId, data); }; - const onSubmit = handleSubmit(async (formData: TenantSettingsForm) => { - if (isSubmitting) { + const onSubmit = handleSubmit( + trySubmitSafe(async (formData: TenantSettingsForm) => { + if (isSubmitting) { + return; + } + + const { + profile: { name, tag }, + } = formData; + await saveData({ name, tag }); + }) + ); + + const onClickDeletionButton = async () => { + if ( + currentTenant?.subscription.planId !== ReservedPlanId.free || + currentTenant.openInvoices.length > 0 + ) { + await showModal({ + title: 'tenants.delete_modal.cannot_delete_title', + ModalContent: t('tenants.delete_modal.cannot_delete_description'), + type: 'alert', + cancelButtonText: 'general.got_it', + }); + return; } - const { - profile: { name, tag }, - } = formData; - await saveData({ name, tag }); - }); - - const onClickDeletionButton = () => { setIsDeletionModalOpen(true); }; @@ -93,21 +103,11 @@ function TenantBasicSettings() { setIsDeletionModalOpen(false); removeTenant(currentTenantId); navigateTenant(''); - } catch (error: unknown) { - setError( - error instanceof Error - ? error - : new Error(JSON.stringify(error, Object.getOwnPropertyNames(error))) - ); } finally { setIsDeleting(false); } }; - if (error) { - return ; - } - return ( <> diff --git a/packages/phrases/src/locales/de/translation/admin-console/tenants.ts b/packages/phrases/src/locales/de/translation/admin-console/tenants.ts index 0076972dd..b6054d09f 100644 --- a/packages/phrases/src/locales/de/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/de/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Wenn Sie fortfahren möchten, geben Sie bitte den Mieter-Namen "{{name}}" zur Bestätigung ein.', delete_button: 'Dauerhaft löschen', + cannot_delete_title: 'Diesen Mandanten kann nicht gelöscht werden', + cannot_delete_description: + 'Entschuldigung, Sie können diesen Mandanten momentan nicht löschen. Stellen Sie sicher, dass Sie sich im kostenlosen Tarif befinden und alle ausstehenden Rechnungen bezahlt haben.', }, tenant_landing_page: { title: 'Du hast noch keinen Mandanten erstellt', diff --git a/packages/phrases/src/locales/en/translation/admin-console/tenants.ts b/packages/phrases/src/locales/en/translation/admin-console/tenants.ts index 526b5b8b7..191e3a277 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'If you would like to proceed, please enter the tenant name "{{name}}" to confirm.', delete_button: 'Permanently delete', + cannot_delete_title: 'Cannot delete this tenant', + cannot_delete_description: + "Sorry, you can't delete this tenant right now. Please make sure you're on the Free Plan and have paid all outstanding billings.", }, tenant_landing_page: { title: "You haven't created a tenant yet", diff --git a/packages/phrases/src/locales/es/translation/admin-console/tenants.ts b/packages/phrases/src/locales/es/translation/admin-console/tenants.ts index 70fb3c384..60da41893 100644 --- a/packages/phrases/src/locales/es/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/es/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Si desea continuar, ingrese el nombre del inquilino "{{name}}" para confirmar.', delete_button: 'Eliminar permanentemente', + cannot_delete_title: 'No se puede eliminar este inquilino', + cannot_delete_description: + 'Lo siento, no puedes eliminar este inquilino en este momento. Asegúrate de estar en el Plan Gratuito y haber pagado todas las facturas pendientes.', }, tenant_landing_page: { title: 'Todavía no has creado un tenant', diff --git a/packages/phrases/src/locales/fr/translation/admin-console/tenants.ts b/packages/phrases/src/locales/fr/translation/admin-console/tenants.ts index 26ac8f22f..be150ce16 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Si vous souhaitez continuer, veuillez entrer le nom du locataire "{{name}}" pour confirmer.', delete_button: 'Supprimer définitivement', + cannot_delete_title: 'Impossible de supprimer ce locataire', + cannot_delete_description: + "Désolé, vous ne pouvez pas supprimer ce locataire pour le moment. Assurez-vous d'être sur le Plan Gratuit et d'avoir payé toutes les factures en cours.", }, tenant_landing_page: { title: "Vous n'avez pas encore créé de locataire", diff --git a/packages/phrases/src/locales/it/translation/admin-console/tenants.ts b/packages/phrases/src/locales/it/translation/admin-console/tenants.ts index eb0ee2b05..3e9b5428d 100644 --- a/packages/phrases/src/locales/it/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/it/translation/admin-console/tenants.ts @@ -42,6 +42,9 @@ const tenants = { description_line3: 'Se vuoi procedere, inserisci il nome del tenant "{{name}}" per confermare.', delete_button: 'Elimina definitivamente', + cannot_delete_title: 'Impossibile eliminare questo locatario', + cannot_delete_description: + 'Spiacente, al momento non è possibile eliminare questo locatario. Verifica di essere nel Piano Gratuito e di aver saldato tutte le fatture pendenti.', }, tenant_landing_page: { title: 'Non hai ancora creato un tenant', diff --git a/packages/phrases/src/locales/ja/translation/admin-console/tenants.ts b/packages/phrases/src/locales/ja/translation/admin-console/tenants.ts index 1557fef2b..251550484 100644 --- a/packages/phrases/src/locales/ja/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/ja/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: '続行する場合は、テナント名 "{{name}}" を入力して確認してください。', delete_button: '完全に削除する', + cannot_delete_title: 'このテナントは削除できません', + cannot_delete_description: + '申し訳ありませんが、現時点ではこのテナントを削除できません。無料プランに登録しており、未払いの請求がないことを確認してください。', }, tenant_landing_page: { title: 'まだテナントを作成していません', diff --git a/packages/phrases/src/locales/ko/translation/admin-console/tenants.ts b/packages/phrases/src/locales/ko/translation/admin-console/tenants.ts index 5f1607130..580665bb6 100644 --- a/packages/phrases/src/locales/ko/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/ko/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: '삭제하려는 테넌트 이름 "{{name}}"을(를) 입력하여 확인하십시오.', delete_button: '영구 삭제', + cannot_delete_title: '이 테넌트를 삭제할 수 없습니다', + cannot_delete_description: + '죄송합니다. 현재이 테넌트를 삭제할 수 없습니다. 무료 플랜에 있고 미결제 청구서가 없는지 확인하십시오.', }, tenant_landing_page: { title: '아직 테넌트를 만들지 않았습니다.', diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/tenants.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/tenants.ts index 824384a55..a60f3cfeb 100644 --- a/packages/phrases/src/locales/pl-pl/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Jeśli chcesz kontynuować, wprowadź nazwę najemcy "{{name}}" w celu potwierdzenia.', delete_button: 'Usuń na stałe', + cannot_delete_title: 'Nie można usunąć tego najemcy', + cannot_delete_description: + 'Przepraszam, nie możesz teraz usunąć tego najemcy. Upewnij się, że korzystasz z planu darmowego i uregulowałeś wszystkie zaległe płatności.', }, tenant_landing_page: { title: 'Nie utworzyłeś jeszcze najemcy', diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/tenants.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/tenants.ts index ede056e87..883761088 100644 --- a/packages/phrases/src/locales/pt-br/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/pt-br/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Se você deseja continuar, digite o nome do locatário "{{name}}" para confirmar.', delete_button: 'Excluir permanentemente', + cannot_delete_title: 'Não é possível excluir este inquilino', + cannot_delete_description: + 'Desculpe, você não pode excluir este inquilino no momento. Certifique-se de estar no Plano Gratuito e ter pago todas as faturas pendentes.', }, tenant_landing_page: { title: 'Você ainda não criou um inquilino', diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/tenants.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/tenants.ts index b9c0a342c..163255264 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Se desejar continuar, introduza o nome do inquilino "{{name}}" para confirmar.', delete_button: 'Eliminar permanentemente', + cannot_delete_title: 'Não é possível apagar este inquilino', + cannot_delete_description: + 'Desculpe, não é possível apagar este inquilino neste momento. Certifique-se de estar no Plano Gratuito e de ter pago todas as faturas em atraso.', }, tenant_landing_page: { title: 'Ainda não criou um inquilino', diff --git a/packages/phrases/src/locales/ru/translation/admin-console/tenants.ts b/packages/phrases/src/locales/ru/translation/admin-console/tenants.ts index 70b8b4449..e6710e716 100644 --- a/packages/phrases/src/locales/ru/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/ru/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Если вы хотите продолжить, введите название арендатора "{{name}}" для подтверждения.', delete_button: 'Навсегда удалить', + cannot_delete_title: 'Нельзя удалить этого арендатора', + cannot_delete_description: + 'Извините, вы не можете удалить этого арендатора прямо сейчас. Пожалуйста, убедитесь, что вы используете бесплатный план и оплатили все невыполненные счета.', }, tenant_landing_page: { title: 'Вы еще не создали арендатора', diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/tenants.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/tenants.ts index 6f36b6ce3..851b4a958 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/tenants.ts @@ -41,6 +41,9 @@ const tenants = { description_line3: 'Devam etmek isterseniz, "{{name}}" kiracı adını onaylamak için yazın.', delete_button: 'Kalıcı olarak sil', + cannot_delete_title: 'Bu kiracı silinemez', + cannot_delete_description: + 'Üzgünüm, bu kiracıyı şu anda silemezsiniz. Ücretsiz Plan üzerinde olduğunuzdan ve tüm ödenmemiş faturaları ödediğinizden emin olun.', }, tenant_landing_page: { title: 'Henüz bir kiracı oluşturmadınız', diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/tenants.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/tenants.ts index a4250bfa6..a0b363564 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/tenants.ts @@ -38,6 +38,9 @@ const tenants = { '在删除帐户之前,也许我们可以帮助您。通过电子邮件联系我们', description_line3: '如果你想继续,请输入租户名 "{{name}}" 确认。', delete_button: '永久删除', + cannot_delete_title: '无法删除此租户', + cannot_delete_description: + '抱歉,您现在无法删除此租户。请确保您处于免费计划并已支付所有未结账单。', }, tenant_landing_page: { title: '你还没有创建租户', diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/tenants.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/tenants.ts index 3fdd43eed..f8169607e 100644 --- a/packages/phrases/src/locales/zh-hk/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/tenants.ts @@ -38,6 +38,9 @@ const tenants = { '在刪除帳戶之前,也許我們可以為您提供幫助。通過電子郵件與我們聯繫', description_line3: '如果您確定要繼續,請輸入租戶名稱 "{{name}}" 以進行確認。', delete_button: '永久刪除', + cannot_delete_title: '無法刪除此租戶', + cannot_delete_description: + '抱歉,您現在無法刪除此租戶。請確保您處於免費計劃並已支付所有未結賬單。', }, tenant_landing_page: { title: '您尚未建立租戶', diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/tenants.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/tenants.ts index 8a1777f2b..b514bbf31 100644 --- a/packages/phrases/src/locales/zh-tw/translation/admin-console/tenants.ts +++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/tenants.ts @@ -38,6 +38,9 @@ const tenants = { '在刪除帳戶之前,也許我們能提供幫助。通過電子郵件與我們聯繫', description_line3: '如果您確定要繼續,請輸入租戶名稱 "{{name}}" 以確認。', delete_button: '永久刪除', + cannot_delete_title: '無法刪除此租戶', + cannot_delete_description: + '抱歉,您現在無法刪除此租戶。請確保您處於免費計劃並已支付所有未結賬單。', }, tenant_landing_page: { title: '您尚未建立租戶',