Skip to content

Commit

Permalink
feat(console,phrases): add bring your ui feature paywall
Browse files Browse the repository at this point in the history
  • Loading branch information
charIeszhao committed Jul 19, 2024
1 parent 6888f53 commit 88fd08f
Show file tree
Hide file tree
Showing 23 changed files with 104 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import * as styles from './index.module.scss';
type Props = {
readonly value?: CustomUiAssets;
readonly onChange: (value: CustomUiAssets) => void;
// eslint-disable-next-line react/boolean-prop-naming
readonly disabled?: boolean;
};

const allowedMimeTypes: AllowedUploadMimeType[] = ['application/zip'];

function CustomUiAssetsUploader({ value, onChange }: Props) {
function CustomUiAssetsUploader({ value, onChange, disabled }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [file, setFile] = useState<File>();
const [error, setError] = useState<string>();
Expand Down Expand Up @@ -48,6 +50,7 @@ function CustomUiAssetsUploader({ value, onChange }: Props) {
if (showUploader) {
return (
<FileUploader<{ customUiAssetId: string }>
disabled={disabled}
allowedMimeTypes={allowedMimeTypes}
maxSize={maxUploadFileSize}
uploadUrl="api/sign-in-exp/default/custom-ui-assets"
Expand Down
2 changes: 1 addition & 1 deletion packages/console/src/components/FeatureTag/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as styles from './index.module.scss';

export { default as BetaTag } from './BetaTag';

type Props = {
export type Props = {
/**
* Whether the tag should be visible. It should be `true` if the tenant's subscription
* plan has NO access to the feature (paywall), but it will always be visible for dev
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
font: var(--font-body-2);
color: var(--color-text-secondary);
}

.featureTag {
margin-left: _.unit(2);
}
}

.description {
Expand Down
4 changes: 4 additions & 0 deletions packages/console/src/ds-components/FormField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ReactElement, ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import Tip from '@/assets/icons/tip.svg';
import FeatureTag, { type Props as FeatureTagProps } from '@/components/FeatureTag';

import type DangerousRaw from '../DangerousRaw';
import DynamicT from '../DynamicT';
Expand All @@ -25,6 +26,7 @@ export type Props = {
readonly headlineSpacing?: 'default' | 'large';
readonly headlineClassName?: string;
readonly tip?: ToggleTipProps['content'];
readonly featureTag?: FeatureTagProps;
};

function FormField({
Expand All @@ -37,6 +39,7 @@ function FormField({
className,
headlineSpacing = 'default',
tip,
featureTag,
headlineClassName,
}: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
Expand All @@ -63,6 +66,7 @@ function FormField({
</IconButton>
</ToggleTip>
)}
{featureTag && <FeatureTag {...featureTag} className={styles.featureTag} />}
<Spacer />
{isRequired && <div className={styles.required}>{t('general.required')}</div>}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,19 @@
}
}

&:hover {
&.disabled {
cursor: not-allowed;
border-color: var(--color-disabled);
color: var(--color-disabled);

.placeholder {
.icon {
color: var(--color-disabled);
}
}
}

&:not(.disabled):hover {
cursor: pointer;
border-color: var(--color-primary);

Expand All @@ -44,7 +56,7 @@
}
}

&.dragActive {
&:not(.disabled).dragActive {
cursor: copy;
background-color: var(--color-hover-variant);
border-color: var(--color-primary);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Ring } from '../../Spinner';
import * as styles from './index.module.scss';

export type Props<T extends Record<string, unknown> = UserAssets> = {
// eslint-disable-next-line react/boolean-prop-naming
readonly disabled?: boolean;
readonly maxSize: number; // In bytes
readonly allowedMimeTypes: AllowedUploadMimeType[];
readonly actionDescription?: string;
Expand All @@ -33,6 +35,7 @@ export type Props<T extends Record<string, unknown> = UserAssets> = {
};

function FileUploader<T extends Record<string, unknown> = UserAssets>({
disabled,
maxSize,
allowedMimeTypes,
actionDescription,
Expand Down Expand Up @@ -119,7 +122,7 @@ function FileUploader<T extends Record<string, unknown> = UserAssets>({

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
disabled: isUploading,
disabled: isUploading || disabled,
multiple: false,
accept: Object.fromEntries(allowedMimeTypes.map((mimeType) => [mimeType, []])),
});
Expand All @@ -131,6 +134,7 @@ function FileUploader<T extends Record<string, unknown> = UserAssets>({
styles.uploader,
Boolean(uploadError) && styles.uploaderError,
isDragActive && styles.dragActive,
disabled && styles.disabled,
className
)}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
@use '@/scss/underscore' as _;

.customCssCodeEditor {
max-height: calc(100vh - 260px);
min-height: 132px; // min-height to show three lines of code
}

.upsell {
margin-top: _.unit(3);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ReservedPlanId } from '@logto/schemas';
import { useContext } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { Trans, useTranslation } from 'react-i18next';

import CustomUiAssetsUploader from '@/components/CustomUiAssetsUploader';
import InlineUpsell from '@/components/InlineUpsell';
import { isDevFeaturesEnabled } from '@/consts/env';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import Card from '@/ds-components/Card';
import CodeEditor from '@/ds-components/CodeEditor';
import FormField from '@/ds-components/FormField';
Expand All @@ -18,6 +22,8 @@ function CustomUiForm() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { getDocumentationUrl } = useDocumentationUrl();
const { control } = useFormContext<SignInExperienceForm>();
const { currentPlan } = useContext(SubscriptionDataContext);
const isBringYourUiEnabled = currentPlan.quota.bringYourUiEnabled;

return (
<Card>
Expand Down Expand Up @@ -79,14 +85,29 @@ function CustomUiForm() {
</Trans>
}
descriptionPosition="top"
featureTag={{
isVisible: !isBringYourUiEnabled,
plan: ReservedPlanId.Pro,
}}
>
<Controller
name="customUiAssets"
control={control}
render={({ field: { onChange, value } }) => (
<CustomUiAssetsUploader value={value} onChange={onChange} />
<CustomUiAssetsUploader
disabled={!isBringYourUiEnabled}
value={value}
onChange={onChange}
/>
)}
/>
{!isBringYourUiEnabled && (
<InlineUpsell
className={brandingStyles.upsell}
for="bring_your_ui"
actionButtonText="upsell.view_plans"
/>
)}
</FormField>
)}
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Upgrade auf einen kostenpflichtigen Plan für benutzerdefinierte JWT-Funktionalität und Premium-Vorteile. Wenn Sie Fragen haben, zögern Sie nicht, uns zu <a>kontaktieren</a>.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ const paywall = {
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Actualiza a un plan de pago para obtener funcionalidades personalizadas de JWT y beneficios premium. No dudes en <a>contactarnos</a> si tienes alguna pregunta.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Aggiorna a un piano a pagamento per la funzionalità JWT personalizzata e benefici premium. Non esitare a <a>contattarci</a> se hai domande.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'사용자 정의 JWT 기능 및 프리미엄 혜택을 위해 유료 플랜으로 업그레이드하세요. 궁금한 점이 있으면 <a>문의하세요</a>.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Ulepsz do płatnego planu, aby uzyskać funkcjonalność niestandardowego JWT i korzyści premium. Jeśli masz jakieś pytania, nie wahaj się <a>skontaktować z nami</a>.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Atualize para um plano pago para funcionalidades de JWT personalizadas e benefícios premium. Não hesite em <a>entrar em contato conosco</a> se tiver alguma dúvida.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Atualize para um plano pago para funcionalidade personalizada JWT e benefícios premium. Não hesite em <a>contactar-nos</a> se tiver alguma dúvida.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Обновите платный план для функциональности пользовательского JWT и дополнительных премиальных возможностей. Если у вас есть вопросы, не стесняйтесь <a>связаться с нами</a>.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const paywall = {
description:
'Özel JWT işlevselliği ve prim avantajları için ücretli bir plana yükseltin. Sorularınız varsa, çekinmeden <a>iletişime geçin</a>.',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ const paywall = {
description:
'升级到付费计划以获取自定义 JWT 功能和高级福利。如有任何问题,请不要犹豫 <a>联系我们</a>。',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ const paywall = {
description:
'升級至付費計劃以獲得自訂 JWT 功能和專業服務。如有任何問題,歡迎隨時<a>聯絡我們</a>。',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ const paywall = {
description:
'升級至付費計劃以解鎖自訂JWT功能和高級福利。如果有任何問題,請隨時<a>聯繹我們</a>。',
},
// UNTRANSLATED
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);

0 comments on commit 88fd08f

Please sign in to comment.